Ticket #6004: 6004.patch
File 6004.patch, 261.3 KB (added by , 11 years ago) |
---|
-
src/bp-attachments/bp-attachments-actions.php
diff --git src/bp-attachments/bp-attachments-actions.php src/bp-attachments/bp-attachments-actions.php index e69de29..df07840 100644
1 <?php 2 /** 3 * Attachments Actions. 4 * 5 * @package BuddyPress 6 * @subpackage Attachments Actions 7 */ 8 9 // Exit if accessed directly 10 defined( 'ABSPATH' ) or exit; 11 12 /** 13 * This function runs when an action is set for a screen: 14 * example.com/members/andy/profile/change-avatar/ [delete-avatar] 15 * 16 * The function will delete the active avatar for a user. 17 * 18 * @since BuddyPress (2.2.0) 19 * 20 * @package BuddyPress 21 * @subpackage Attachments Actions 22 * 23 * @uses bp_is_user_change_avatar() 24 * @uses bp_is_action_variable() 25 * @uses bp_is_my_profile() 26 * @uses bp_current_user_can() 27 * @uses bp_attachments_delete_existing_avatar() 28 * @uses bp_displayed_user_id() 29 * @uses bp_core_add_message() 30 * @uses bp_core_redirect() 31 */ 32 function bp_attachments_action_xprofile_delete_avatar() { 33 34 if ( ! bp_is_user_change_avatar() || ! bp_is_action_variable( 'delete-avatar', 0 ) ) { 35 return false; 36 } 37 38 // Check the nonce 39 check_admin_referer( 'bp_delete_avatar_link' ); 40 41 if ( ! bp_is_my_profile() && ! bp_current_user_can( 'bp_moderate' ) ) { 42 return false; 43 } 44 45 if ( bp_attachments_delete_existing_avatar( array( 'item_id' => bp_displayed_user_id() ) ) ) { 46 bp_core_add_message( __( 'Your profile photo was deleted successfully!', 'buddypress' ) ); 47 } else { 48 bp_core_add_message( __( 'There was a problem deleting your profile photo; please try again.', 'buddypress' ), 'error' ); 49 } 50 51 bp_core_redirect( wp_get_referer() ); 52 } 53 add_action( 'bp_actions', 'bp_attachments_action_xprofile_delete_avatar' ); 54 55 /** 56 * Handle the display of a new group's Avatar create step. 57 * 58 * @since BuddyPress (2.2.0) 59 * 60 * @package BuddyPress 61 * @subpackage Attachments Actions 62 * 63 * @param int $group_id the new group id 64 * @uses bp_is_active() 65 * @uses bp_get_groups_current_create_step() 66 * @uses buddypress() 67 * @uses bp_get_new_group_id() 68 * @uses bp_attachments_avatar_handle_upload() 69 * @uses is_wp_error() 70 * @uses bp_core_add_message() 71 * @uses bp_attachments_avatar_handle_crop() 72 */ 73 function bp_attachments_action_group_avatar_create_step( $group_id = 0 ) { 74 if ( ! bp_is_active( 'groups' ) && 'group-avatar' != bp_get_groups_current_create_step() && ! isset( $_POST['upload'] ) ) { 75 return; 76 } 77 78 $bp = buddypress(); 79 80 if ( ! isset( $bp->avatar_admin ) ) { 81 $bp->avatar_admin = new stdClass(); 82 } 83 84 if ( empty( $group_id ) ) { 85 $group_id = bp_get_new_group_id(); 86 } 87 88 if ( ! empty( $_FILES ) && isset( $_POST['upload'] ) ) { 89 90 // Pass the file to the avatar upload handler 91 $uploaded_avatar = bp_attachments_avatar_handle_upload( $_FILES, 'groups', $group_id ); 92 93 if ( is_wp_error( $uploaded_avatar ) ) { 94 bp_core_add_message( $uploaded_avatar->get_error_message(), 'error' ); 95 96 // Go to crop step 97 } else { 98 // Avoid some error messages to be output if 99 // everything is ok. 100 $bp->template_message = false; 101 $bp->avatar_admin->step = 'crop-image'; 102 103 // Make sure we include the jQuery jCrop file for image cropping 104 add_action( 'wp_print_scripts', 'bp_attachments_add_jquery_cropper' ); 105 } 106 } 107 108 // If the image cropping is done, crop the image and save a full/thumb version 109 if ( isset( $_POST['avatar-crop-submit'] ) && isset( $_POST['upload'] ) ) { 110 111 $args = array( 112 'object' => 'group', 113 'avatar_dir' => 'avatar_group_dir', 114 'item_id' => $group_id, 115 'original_file' => $_POST['image_src'], 116 'crop_x' => $_POST['x'], 117 'crop_y' => $_POST['y'], 118 'crop_w' => $_POST['w'], 119 'crop_h' => $_POST['h'] 120 ); 121 122 if ( ! bp_attachments_avatar_handle_crop( $args ) ) { 123 bp_core_add_message( __( 'There was an error saving the group profile photo, please try uploading again.', 'buddypress' ), 'error' ); 124 } else { 125 bp_core_add_message( __( 'The group profile photo was uploaded successfully!', 'buddypress' ) ); 126 } 127 } 128 } 129 add_action( 'bp_groups_avatar_create_step', 'bp_attachments_action_group_avatar_create_step', 10, 1 ); 130 131 /** 132 * Add the specific templates needed by BP Attachments Editor 133 * 134 * @since BuddyPress (2.2.0) 135 */ 136 function bp_attachment_load_backbone_tmpl() { 137 ?> 138 <script type="text/html" id="tmpl-bp-attachment-details"> 139 <h3> 140 <?php _e('Attachment Details'); ?> 141 142 <span class="settings-save-status"> 143 <span class="spinner"></span> 144 <span class="saved"><?php esc_html_e('Saved.'); ?></span> 145 </span> 146 </h3> 147 <div class="attachment-info"> 148 <div class="thumbnail"> 149 <# if ( data.uploading ) { #> 150 <div class="media-progress-bar"><div></div></div> 151 <# } else if ( 'image' === data.type ) { #> 152 <img src="{{ data.size.url }}" draggable="false" /> 153 <# } else { #> 154 <img src="{{ data.icon }}" class="icon" draggable="false" /> 155 <# } #> 156 </div> 157 <div class="details"> 158 <div class="filename">{{ data.filename }}</div> 159 <div class="uploaded">{{ data.dateFormatted }}</div> 160 161 <# if ( 'image' === data.type && ! data.uploading ) { #> 162 <# if ( data.width && data.height ) { #> 163 <div class="dimensions">{{ data.width }} × {{ data.height }}</div> 164 <# } #> 165 166 <# if ( data.can.save ) { #> 167 <a class="edit-bp-attachment" href="{{ data.editLink }}"><?php _e( 'Edit Options', 'buddypress' ); ?></a> 168 <# } #> 169 <# } #> 170 171 <# if ( data.fileLength ) { #> 172 <div class="file-length"><?php _e( 'Length:' ); ?> {{ data.fileLength }}</div> 173 <# } #> 174 175 <# if ( ! data.uploading && data.can.remove ) { #> 176 <?php if ( MEDIA_TRASH ): ?> 177 <a class="trash-attachment" href="#"><?php _e( 'Trash' ); ?></a> 178 <?php else: ?> 179 <a class="delete-attachment" href="#"><?php _e( 'Delete Permanently' ); ?></a> 180 <?php endif; ?> 181 <# } #> 182 183 <div class="compat-meta"> 184 <# if ( data.compat && data.compat.meta ) { #> 185 {{{ data.compat.meta }}} 186 <# } #> 187 </div> 188 </div> 189 </div> 190 191 <# var maybeReadOnly = data.can.save || data.allowLocalEdits ? '' : 'readonly'; #> 192 <label class="setting" data-setting="title"> 193 <span><?php _e('Title'); ?></span> 194 <input type="text" value="{{ data.title }}" {{ maybeReadOnly }} /> 195 </label> 196 <label class="setting" data-setting="description"> 197 <span><?php _e('Description'); ?></span> 198 <textarea {{ maybeReadOnly }}>{{ data.description }}</textarea> 199 </label> 200 </script> 201 202 <script type="text/html" id="tmpl-avatar"> 203 <div class="avatar-preview"> 204 <# if ( data.uploading ) { #> 205 <div class="media-progress-bar"><div></div></div> 206 <# } else { #> 207 <div class="resized"> 208 <div class="centered"> 209 <img src="{{ data.size.url }}" draggable="false" id="avatar-to-crop" /> 210 </div> 211 </div> 212 <# } #> 213 </div> 214 </script> 215 216 <script type="text/html" id="tmpl-bp-avatar-details"> 217 <h3> 218 <?php _e('Avatar preview', 'buddypress'); ?> 219 </h3> 220 <div class="attachment-info"> 221 <div class="avatar-thumb" style="width:<?php echo bp_core_avatar_full_width();?>px;height:<?php echo bp_core_avatar_full_height();?>px;overflow:hidden"> 222 <img draggable="false" id="avatar-crop-preview" /> 223 </div> 224 </div> 225 </script> 226 227 <script type="text/html" id="tmpl-bp-preview"> 228 <# if ( data.id ) { #> 229 <div class="centered"> 230 <img src="{{ data.img }}" style="max-width:100%"/> 231 </div> 232 <# } #> 233 </script> 234 <?php 235 } 236 add_action( 'print_media_templates', 'bp_attachment_load_backbone_tmpl' ); 237 238 239 /** 240 * Handle uploads if no-js 241 * 242 * @since BuddyPress (2.2.0) 243 */ 244 function bp_attachments_catch_upload() { 245 246 if ( ! empty( $_POST['bp_attachment_upload'] ) ) { 247 248 check_admin_referer( 'bp_attachments_upload', 'bp_attachments_upload_nonce' ); 249 250 $redirect = $_POST['_wp_http_referer']; 251 252 $file_name = 'bp_attachment_file'; 253 254 if ( ! empty( $_POST['file_data'] ) ) { 255 $file_name = $_POST['file_data']; 256 } 257 258 if ( ! empty( $_FILES[ $file_name ] ) ) { 259 260 $args = array(); 261 262 if ( ! empty( $_POST['item_id'] ) ) 263 $args['item_id'] = absint( $_POST['item_id'] ); 264 265 if ( ! empty( $_POST['item_type'] ) ) { 266 $args['item_type'] = $_POST['item_type']; 267 } else { 268 $args['item_type'] = 'attachment'; 269 } 270 271 if ( ! empty( $_POST['component'] ) ) 272 $args['component'] = $_POST['component']; 273 274 if ( ! empty( $_POST['action'] ) ) 275 $args['action'] = $_POST['action']; 276 277 // We don't categorized members as a bp_component term 278 if ( 'members' == $args['component'] ) { 279 unset( $args['component'] ); 280 } 281 282 $cap_args = false; 283 284 if ( ! empty( $args['component'] ) ) { 285 $cap_args = array( 'component' => $args['component'], 'item_id' => $args['item_id'] ); 286 } 287 288 // capability check 289 if ( ! bp_attachments_current_user_can( 'publish_bp_attachments', $cap_args ) ) { 290 bp_core_add_message( __( 'Error: you are not allowed to create this attachment.', 'buddypress' ), 'error' ); 291 bp_core_redirect( $redirect ); 292 } 293 294 // Dealing with an Avatar 295 if ( 'avatar' == $args['item_type'] ) { 296 $avatar = bp_attachments_avatar_handle_upload( $_FILES, $args['component'], $args['item_id'] ); 297 298 if ( ! is_wp_error( $avatar ) ) { 299 switch ( $component ) { 300 case 'groups' : 301 $object = 'group'; 302 $avatar_dir = 'avatar_group_dir'; 303 break; 304 305 case 'blogs' : 306 $object = 'blog'; 307 $avatar_dir = 'avatar_blog_dir'; 308 break; 309 310 case 'xprofile' : 311 default : 312 $object = 'user'; 313 $avatar_dir = 'avatar_user_dir'; 314 break; 315 } 316 317 $crop = bp_attachments_avatar_handle_crop( array( 318 'object' => $object, 319 'avatar_dir' => $avatar_dir, 320 'item_id' => $args['item_id'], 321 'original_file' => $avatar, 322 ) ); 323 324 if ( ! empty( $crop ) ) { 325 $attachment_id = $crop; 326 } else { 327 $attachment_id = new WP_Error( 'crop_error', sprintf( __( 'There was an error saving the %s avatar, please try uploading again.', 'buddypress' ), $object ) ); 328 } 329 } else { 330 $attachment_id = $avatar; 331 } 332 // Dealing with an Attachment 333 } else { 334 $attachment_id = bp_attachments_handle_upload( $args ); 335 } 336 337 if ( is_wp_error( $attachment_id ) ) { 338 bp_core_add_message( sprintf( __( 'Error: %s', 'buddypress' ), $attachment_id->get_error_message() ), 'error' ); 339 } else { 340 bp_core_add_message( sprintf( __( '%s successfully uploaded', 'buddypress' ), ucfirst( $args['item_type'] ) ) ); 341 } 342 343 bp_core_redirect( $redirect ); 344 } 345 } 346 } 347 add_action( 'bp_actions', 'bp_attachments_catch_upload' ); -
src/bp-attachments/bp-attachments-admin.php
diff --git src/bp-attachments/bp-attachments-admin.php src/bp-attachments/bp-attachments-admin.php index e69de29..7c3f41b 100644
1 <?php 2 /** 3 * Attachments Admin. 4 * 5 * A media component, for others ! 6 * 7 * @package BuddyPress 8 * @subpackage Attachments Administration 9 */ 10 11 // Exit if accessed directly 12 defined( 'ABSPATH' ) or exit; 13 14 if ( ! class_exists( 'BP_Attachment_Admin' ) ) : 15 /** 16 * Load BP Attachments admin area. 17 * 18 * @package BuddyPress 19 * @subpackage Attachments Administration 20 * 21 * @since BuddyPress (2.2.0) 22 */ 23 class BP_Attachments_Admin { 24 /** 25 * Setup BP Attachments Admin. 26 * 27 * @access public 28 * @since BuddyPress (2.2.0) 29 * 30 * @uses buddypress() to get BuddyPress main instance 31 */ 32 public static function register_attachments_admin() { 33 if( ! is_admin() ) 34 return; 35 36 $bp = buddypress(); 37 38 if( empty( $bp->attachments->admin ) ) { 39 $bp->attachments->admin = new self; 40 } 41 42 return $bp->attachments->admin; 43 } 44 45 /** 46 * Constructor method. 47 * 48 * @access public 49 * @since BuddyPress (2.2.0) 50 */ 51 public function __construct() { 52 $this->setup_actions(); 53 } 54 55 /** 56 * Set admin-related actions and filters. 57 * 58 * @access private 59 * @since BuddyPress (2.2.0) 60 */ 61 private function setup_actions() { 62 add_action( 'bp_groups_admin_meta_boxes', array( $this, 'group_avatar' ) ); 63 add_action( 'bp_members_admin_xprofile_metabox', array( $this, 'user_avatar' ), 10, 2 ); 64 } 65 66 /** 67 * Add a metabox to edit Group's Avatar 68 * 69 * @access public 70 * @since BuddyPress (2.2.0) 71 */ 72 public function group_avatar() { 73 add_meta_box( 74 'bp_groups_avatar', 75 _x( 'Avatar', 'group admin edit screen', 'buddypress' ), 76 array( &$this, 'group_avatar_metabox' ), 77 get_current_screen()->id, 78 'side', 79 'low' 80 ); 81 } 82 83 /** 84 * Displays the metabox to edit Group's Avatar 85 * 86 * @access public 87 * @since BuddyPress (2.2.0) 88 */ 89 public function group_avatar_metabox( $item = null ) { 90 if ( empty( $item ) ) 91 return; 92 ?> 93 <div id="groups-avatar"> 94 <?php 95 // Displays the current avatar and a link to delete it. 96 if ( bp_get_group_has_avatar( $item->id ) ) { 97 echo bp_core_fetch_avatar( array( 'item_id' => $item->id, 'object' => 'group', 'type' => 'full' ) );?> 98 <p><a href="#" id="remove-groups-avatar"><?php esc_html_e( 'Remove Avatar', 'buddypress' ); ?></a></p> 99 <?php 100 } 101 ?> 102 </div> 103 <?php 104 // Displays the button to Change the avatar. 105 bp_attachments_browser( 'bp-avatar-upload', array( 106 'item_id' => $item->id, 107 'component' => 'groups', 108 'item_type' => 'avatar', 109 'btn_caption' => __( 'Edit Avatar', 'buddypress' ), 110 'multi_selection' => false, 111 'action' => 'bp_avatar_upload', 112 'file_data_name' => 'file', 113 'btn_class' => 'attachments-new-avatar' 114 ) ); 115 } 116 117 /** 118 * Add a metabox to edit User's Avatar 119 * 120 * @access public 121 * @since BuddyPress (2.2.0) 122 */ 123 public function user_avatar( $user_id = 0, $screen_id = '' ) { 124 // Set the screen ID if none was passed 125 if ( empty( $screen_id ) ) { 126 $screen_id = buddypress()->members->admin->user_page; 127 } 128 129 if ( bp_attachments_avatar_is_enabled() ) { 130 // Avatar Metabox 131 add_meta_box( 132 'bp_xprofile_avatar', 133 _x( 'Profile Photo', 'attachments user-admin edit screen', 'buddypress' ), 134 array( $this, 'user_avatar_metabox' ), 135 $screen_id, 136 'side', 137 'low' 138 ); 139 } 140 } 141 142 /** 143 * Displays the metabox to edit User's Avatar 144 * 145 * @access public 146 * @since BuddyPress (2.2.0) 147 */ 148 public function user_avatar_metabox( $user = null ) { 149 if ( empty( $user->ID ) ) { 150 return; 151 } ?> 152 153 <div id="xprofile-avatar"> 154 155 <?php echo bp_core_fetch_avatar( array( 156 'item_id' => $user->ID, 157 'object' => 'user', 158 'type' => 'full', 159 'title' => $user->display_name 160 ) ); ?> 161 162 <?php if ( bp_get_user_has_avatar( $user->ID ) ) : ?> 163 164 <p><a href="#" id="remove-xprofile-avatar"><?php esc_html_e( 'Remove Avatar', 'buddypress' ); ?></a></p> 165 166 <?php endif; ?> 167 168 </div> 169 <?php 170 // Displays the button to Change the avatar. 171 bp_attachments_browser( 'bp-avatar-upload', array( 172 'item_id' => $user->ID, 173 'component' => 'xprofile', 174 'item_type' => 'avatar', 175 'btn_caption' => __( 'Edit Avatar', 'buddypress' ), 176 'multi_selection' => false, 177 'action' => 'bp_avatar_upload', 178 'file_data_name' => 'file', 179 'btn_class' => 'attachments-new-avatar' 180 ) ); 181 } 182 } 183 endif; // class_exists check 184 185 // Load the BP Attachments admin 186 add_action( 'bp_init', array( 'BP_Attachments_Admin','register_attachments_admin' ) ); -
src/bp-attachments/bp-attachments-ajax.php
diff --git src/bp-attachments/bp-attachments-ajax.php src/bp-attachments/bp-attachments-ajax.php index e69de29..f1021c3 100644
1 <?php 2 /** 3 * Attachments Ajax. 4 * 5 * @package BuddyPress 6 * @subpackage Attachments Ajax 7 */ 8 9 // Exit if accessed directly 10 defined( 'ABSPATH' ) or exit; 11 12 /** 13 * Upload an avatar from "BP Attachments Editor". 14 * 15 * Avatars are not handled the same way than attachments 16 * 1- no post type "bp_attachment" is created 17 * 2- it doesn't change anything to the way BuddyPress manage avatars 18 * 19 * @since BuddyPress (2.2.0) 20 */ 21 function bp_attachments_avatar_ajax_upload(){ 22 //nonce check 23 check_ajax_referer( 'media-form' ); 24 25 $item_id = ! empty( $_REQUEST['item_id'] ) ? intval( $_REQUEST['item_id'] ) : null; 26 $component = ! empty( $_REQUEST['component'] ) ? sanitize_title( $_REQUEST['component'] ) : ''; 27 $context = ! empty( $_REQUEST['item_type'] ) ? sanitize_title( $_REQUEST['item_type'] ) : ''; 28 29 $cap_args = false; 30 if ( ! empty( $component ) ) { 31 $cap_args = array( 'component' => $component, 'item_id' => $item_id ); 32 } 33 34 // We don't categorized members as a bp_component term 35 if ( 'members' == $component ) { 36 $cap_args = false; 37 } 38 39 // capability check 40 if ( ! bp_attachments_current_user_can( 'edit_bp_attachments', $cap_args ) ) { 41 wp_die(); 42 } 43 44 $avatar = bp_attachments_avatar_handle_upload( $_FILES, $component, $item_id, true ); 45 46 if ( is_wp_error( $avatar ) ) { 47 wp_send_json_error( array( 48 'message' => $avatar->get_error_message(), 49 'filename' => $_FILES['file']['name'], 50 ) ); 51 } 52 53 wp_send_json_success( $avatar ); 54 } 55 add_action( 'wp_ajax_bp_avatar_upload', 'bp_attachments_avatar_ajax_upload' ); 56 57 /** 58 * Crop an avatar from "BP Attachments Editor". 59 * 60 * Avatars are not handled the same way than attachments 61 * 1- no post type "bp_attachment" is created 62 * 2- it doesn't change anything to the way BuddyPress manage avatars 63 * 64 * @since BuddyPress (2.2.0) 65 */ 66 function bp_attachments_set_avatar() { 67 $json = ! empty( $_REQUEST['json'] ); // New-style request 68 69 check_ajax_referer( 'bp_attachments_avatar', 'nonce' ); 70 71 if ( empty( $_REQUEST['item_id'] ) || empty( $_REQUEST['object'] ) || empty( $_REQUEST['component'] ) ) { 72 wp_die(0); 73 } 74 75 $component = esc_html( $_REQUEST['component'] ); 76 $item_id = absint( $_REQUEST['item_id'] ); 77 $object = esc_html( $_REQUEST['object'] ); 78 79 $cap_args = false; 80 if ( ! empty( $component ) ) { 81 $cap_args = array( 'component' => $component, 'item_id' => $item_id ); 82 } 83 84 // We don't categorized members as a bp_component term 85 if ( 'members' == $component ) { 86 $cap_args = false; 87 } 88 89 // capability check 90 if ( ! bp_attachments_current_user_can( 'edit_bp_attachments', $cap_args ) ) { 91 wp_die(); 92 } 93 94 // Handle crop 95 if ( bp_attachments_avatar_handle_crop( $_REQUEST ) ) { 96 $return = bp_core_fetch_avatar( array( 97 'object' => $object, 98 'item_id' => $item_id, 99 'html' => true, 100 'type' => 'full', 101 ) ); 102 103 $return .= '<p><a href="#" id="remove-' . $component . '-avatar">' . esc_html__( 'Remove Avatar', 'buddypress' ) . '</a></p>'; 104 105 if ( ! empty( $json ) ) { 106 wp_send_json_success( $return ); 107 } else { 108 wp_die( $return ); 109 } 110 } else { 111 wp_die( 0 ); 112 } 113 } 114 add_action( 'wp_ajax_bp_attachments_set_avatar', 'bp_attachments_set_avatar' ); 115 116 /** 117 * Delete an avatar from "BP Attachments Editor". 118 * 119 * Avatars are not handled the same way than attachments 120 * 1- no post type "bp_attachment" is created 121 * 2- it doesn't change anything to the way BuddyPress manage avatars 122 * 123 * @since BuddyPress (2.2.0) 124 */ 125 function bp_attachments_delete_avatar() { 126 $json = ! empty( $_REQUEST['json'] ); // New-style request 127 128 check_ajax_referer( 'bp_attachments_avatar', 'nonce' ); 129 130 if ( empty( $_REQUEST['item_id'] ) || empty( $_REQUEST['object'] ) ) { 131 wp_die(0); 132 } 133 134 $item_id = absint( $_REQUEST['item_id'] ); 135 $object = esc_html( $_REQUEST['object'] ); 136 137 $cap_args = false; 138 if ( ! empty( $object ) ) { 139 $cap_args = array( 'component' => $object, 'item_id' => $item_id ); 140 } 141 142 // We don't categorized members as a bp_component term 143 if ( 'members' == $object ) { 144 $cap_args = false; 145 } 146 147 // capability check 148 if ( ! bp_attachments_current_user_can( 'edit_bp_attachments', $cap_args ) ) { 149 wp_die(); 150 } 151 152 if ( bp_attachments_delete_existing_avatar( array( 'item_id' => $item_id, 'object' => $object ) ) ) { 153 if ( ! empty( $json ) ) { 154 wp_send_json_success( 1 ); 155 } else { 156 wp_die( 1 ); 157 } 158 } else { 159 wp_die(0); 160 } 161 } 162 add_action( 'wp_ajax_bp_attachments_delete_avatar', 'bp_attachments_delete_avatar' ); 163 164 /** 165 * Query attachments for the "BP Attachments Editor". 166 * 167 * @since BuddyPress (2.2.0) 168 */ 169 function bp_attachments_query() { 170 $query = isset( $_REQUEST['query'] ) ? (array) $_REQUEST['query'] : array(); 171 $query = array_intersect_key( $query, array_flip( array( 172 's', 'order', 'orderby', 'posts_per_page', 'paged', 'post_mime_type', 173 'post_parent', 'post__in', 'post__not_in', 'item_type', 'item_id', 'component' 174 ) ) ); 175 176 $args = array( 177 'show_private' => false, // this could be checking bp_is_my_profile() or current user is a group admin 178 'user_id' => bp_loggedin_user_id(), 179 'per_page' => $query['posts_per_page'], 180 'page' => $query['paged'], 181 'orderby' => $query['orderby'], 182 'order' => $query['order'], 183 ); 184 185 if ( ! empty( $query['item_id'] ) ) { 186 $args['item_ids'] = array( $query['item_id'] ); 187 } 188 189 if ( ! empty( $query['component'] ) && 'members' != $query['component'] ) { 190 $args['component'] = $query['component']; 191 } 192 193 if ( ! empty( $query['s'] ) ) 194 $args['search'] = $query['s']; 195 196 $query = bp_attachments_get_attachments( $args ); 197 198 $attachments = array_map( 'bp_attachments_prepare_attachment_for_js', $query['attachments'] ); 199 $attachments = array_filter( $attachments ); 200 201 wp_send_json_success( $attachments ); 202 } 203 add_action( 'wp_ajax_query_bp_attachments', 'bp_attachments_query' ); 204 205 /** 206 * Process an attachment upload requested in "BP Attachments Editor". 207 * 208 * @since BuddyPress (2.2.0) 209 */ 210 function bp_attachments_upload() { 211 //nonce check 212 check_ajax_referer( 'media-form' ); 213 214 $r = bp_parse_args( $_REQUEST, array( 215 'item_id' => 0, 216 'component' => '', 217 'item_type' => 'attachment', 218 'action' => 'bp_attachments_upload', 219 'file_id' => 'bp_attachment_file' 220 ), 'attachments_ajax_upload' ); 221 222 // We don't categorized members as a bp_component term 223 if ( 'members' == $r['component'] ) { 224 unset( $r['component'] ); 225 } 226 $cap_args = false; 227 228 if ( ! empty( $r['component'] ) ) { 229 $cap_args = array( 'component' => $r['component'], 'item_id' => $r['item_id'] ); 230 } 231 232 // capability check 233 if ( ! bp_attachments_current_user_can( 'publish_bp_attachments', $cap_args ) ) { 234 wp_die(); 235 } 236 237 $attachment_id = bp_attachments_handle_upload( $r ); 238 239 if ( is_wp_error( $attachment_id ) ) { 240 wp_send_json_error( array( 241 'message' => $attachment_id->get_error_message(), 242 'filename' => $_FILES['bp_attachment_file']['name'], 243 ) ); 244 } 245 246 if ( ! $attachment = bp_attachments_prepare_attachment_for_js( $attachment_id ) ) { 247 wp_die(); 248 } 249 250 wp_send_json_success( $attachment ); 251 } 252 add_action( 'wp_ajax_bp_attachments_upload', 'bp_attachments_upload' ); 253 254 /** 255 * Delete an attachment from "BP Attachments Editor". 256 * 257 * @since BuddyPress (2.2.0) 258 */ 259 function bp_attachments_ajax_delete_attachment( $action ) { 260 if ( empty( $action ) ) { 261 $action = 'delete_bp_attachment'; 262 } 263 264 $id = isset( $_POST['id'] ) ? (int) $_POST['id'] : 0; 265 266 check_ajax_referer( "{$action}_$id" ); 267 268 if ( ! bp_attachments_current_user_can( 'delete_bp_attachment', $id ) ) { 269 wp_die( -1 ); 270 } 271 272 if ( bp_attachments_delete_attachment( $id ) ) { 273 wp_die( 1 ); 274 } else { 275 wp_die( 0 ); 276 } 277 } 278 add_action( 'wp_ajax_delete_bp_attachment', 'bp_attachments_ajax_delete_attachment' ); 279 280 /** 281 * Update an attachment from "BP Attachments Editor". 282 * 283 * @since BuddyPress (2.2.0) 284 */ 285 function bp_attachments_ajax_update_attachment() { 286 if ( ! isset( $_REQUEST['id'] ) || ! isset( $_REQUEST['changes'] ) ) { 287 wp_send_json_error(); 288 } 289 290 if ( ! $id = absint( $_REQUEST['id'] ) ) { 291 wp_send_json_error(); 292 } 293 294 check_ajax_referer( 'update_bp_attachment_' . $id, 'nonce' ); 295 296 if ( ! bp_attachments_current_user_can( 'edit_bp_attachment', $id ) ) { 297 wp_send_json_error(); 298 } 299 300 $changes = $_REQUEST['changes']; 301 302 $update = array( 'id' => $id, 'ajax' => true ); 303 304 if ( isset( $changes['title'] ) ) { 305 $update['title'] = $changes['title']; 306 } 307 308 if ( isset( $changes['description'] ) ) { 309 $update['description'] = $changes['description']; 310 } 311 312 if ( ! bp_attachments_update_attachment( $update ) ) { 313 wp_send_json_error(); 314 } 315 316 wp_send_json_success(); 317 } 318 add_action( 'wp_ajax_update_bp_attachment', 'bp_attachments_ajax_update_attachment' ); -
src/bp-attachments/bp-attachments-caps.php
diff --git src/bp-attachments/bp-attachments-caps.php src/bp-attachments/bp-attachments-caps.php index e69de29..973d9ce 100644
1 <?php 2 /** 3 * Attachments caps 4 * 5 * @package BuddyPress 6 * @subpackage Caps 7 */ 8 9 // Exit if accessed directly 10 defined( 'ABSPATH' ) or exit; 11 12 /** 13 * bp_attachment post type caps 14 * 15 * @since BuddyPress (2.2.0) 16 */ 17 function bp_attachments_get_attachment_caps() { 18 return apply_filters( 'bp_attachments_get_attachment_caps', array ( 19 'edit_posts' => 'edit_bp_attachments', 20 'edit_others_posts' => 'edit_others_bp_attachments', 21 'publish_posts' => 'publish_bp_attachments', 22 'read_private_posts' => 'read_private_bp_attachments', 23 'delete_posts' => 'delete_bp_attachments', 24 'delete_others_posts' => 'delete_others_bp_attachments' 25 ) ); 26 } 27 28 /** 29 * bp_component taxonomy caps 30 * 31 * @since BuddyPress (2.2.0) 32 */ 33 function bp_attachments_get_component_caps() { 34 return apply_filters( 'bp_attachments_get_component_caps', array ( 35 'manage_terms' => 'manage_bp_components', 36 'edit_terms' => 'edit_bp_components', 37 'delete_terms' => 'delete_bp_components', 38 'assign_terms' => 'assign_bp_components' 39 ) ); 40 } 41 42 /** 43 * Map capabilities 44 * 45 * @since BuddyPress (2.2.0) 46 * 47 * @param array $caps 48 * @param string $cap 49 * @param integer $user_id 50 * @param array $args 51 * @return array $caps 52 */ 53 function bp_attachments_map_meta_caps( $caps = array(), $cap = '', $user_id = 0, $args = array() ) { 54 55 // What capability is being checked? 56 switch ( $cap ) { 57 58 /** Reading ***********************************************************/ 59 60 case 'read_private_bp_attachments' : 61 62 if ( ! empty( $args[0] ) ) { 63 // Get the post 64 $_post = get_post( $args[0] ); 65 if ( ! empty( $_post ) ) { 66 67 // Get caps for post type object 68 $post_type = get_post_type_object( $_post->post_type ); 69 $caps = array(); 70 71 // Allow author to edit his attachment 72 if ( $user_id == $_post->post_author ) { 73 // In a network, most members has no role 74 $caps[] = 'exist'; 75 76 // @todo private attachments will need other rules 77 78 // Admins can always edit 79 } else if ( user_can( $user_id, 'manage_options' ) ) { 80 $caps = array( 'manage_options' ); 81 } else { 82 $caps[] = $post_type->cap->edit_others_posts; 83 } 84 85 } 86 } 87 88 89 break; 90 91 /** Publishing ********************************************************/ 92 93 case 'publish_bp_attachments' : 94 95 if ( bp_is_my_profile() ) { 96 // In a network, most members has no role 97 $caps = array( 'exist' ); 98 } 99 100 if ( ! empty( $args[0] ) && is_a( $args[0], 'BP_Attachments_Can' ) ) { 101 102 if ( ! empty( $args[0]->component ) && ! empty( $args[0]->item_id ) ){ 103 switch( $args[0]->component ) { 104 case 'groups': 105 if( groups_is_user_member( $user_id, $args[0]->item_id ) ) { 106 // In a network, most members has no role 107 $caps = array( 'exist' ); 108 } 109 break; 110 111 // and so on for other components 112 } 113 } 114 115 } 116 117 // Admins can always publish 118 if ( user_can( $user_id, 'manage_options' ) ) { 119 $caps = array( 'manage_options' ); 120 } 121 122 break; 123 124 /** Editing ***********************************************************/ 125 126 case 'edit_bp_attachments' : 127 128 if ( bp_is_my_profile() ) { 129 // In a network, most members has no role 130 $caps = array( 'exist' ); 131 } 132 133 if ( ! empty( $args[0] ) && is_a( $args[0], 'BP_Attachments_Can' ) ) { 134 135 if ( ! empty( $args[0]->component ) && ! empty( $args[0]->item_id ) ){ 136 switch( $args[0]->component ) { 137 case 'groups': 138 case 'group' : 139 if( groups_is_user_admin( $user_id, $args[0]->item_id ) ) { 140 // In a network, most members has no role 141 $caps = array( 'exist' ); 142 } 143 break; 144 145 // and so on for other components 146 } 147 } 148 149 } 150 151 // Admins can always edit 152 if ( user_can( $user_id, 'manage_options' ) ) { 153 $caps = array( 'manage_options' ); 154 } 155 156 break; 157 158 // Used primarily in wp-admin 159 case 'edit_others_bp_attachments' : 160 161 // Admins can always edit 162 if ( user_can( $user_id, 'manage_options' ) ) { 163 $caps = array( 'manage_options' ); 164 } 165 166 break; 167 168 // Used everywhere 169 case 'edit_bp_attachment' : 170 171 // Get the post 172 $_post = get_post( $args[0] ); 173 if ( ! empty( $_post ) ) { 174 175 // Get caps for post type object 176 $post_type = get_post_type_object( $_post->post_type ); 177 $caps = array(); 178 179 // Allow author to edit his attachment 180 if ( $user_id == $_post->post_author ) { 181 // In a network, most members has no role 182 $caps[] = 'exist'; 183 184 // Admins can always edit 185 } else if ( user_can( $user_id, 'manage_options' ) ) { 186 $caps = array( 'manage_options' ); 187 } else { 188 $caps[] = $post_type->cap->edit_others_posts; 189 } 190 191 } 192 193 break; 194 195 /** Deleting **********************************************************/ 196 197 case 'delete_bp_attachment' : 198 199 // Get the post 200 $_post = get_post( $args[0] ); 201 if ( ! empty( $_post ) ) { 202 203 // Get caps for post type object 204 $post_type = get_post_type_object( $_post->post_type ); 205 $caps = array(); 206 207 // Allow author to edit his attachment 208 if ( $user_id == $_post->post_author ) { 209 // In a network, most members has no role 210 $caps[] = 'exist'; 211 212 // Admins can always edit 213 } else if ( user_can( $user_id, 'manage_options' ) ) { 214 $caps = array( 'manage_options' ); 215 } else { 216 $caps[] = $post_type->cap->delete_others_posts; 217 } 218 } 219 220 break; 221 222 // Moderation override 223 case 'delete_bp_attachments' : 224 case 'delete_others_bp_attachments' : 225 226 // Moderators can always delete 227 if ( user_can( $user_id, 'manage_options' ) ) { 228 $caps = array( 'manage_options' ); 229 } 230 231 break; 232 233 /** Admin *************************************************************/ 234 235 case 'bp_attachments_moderate' : 236 237 // Admins can always moderate 238 if ( user_can( $user_id, 'manage_options' ) ) { 239 $caps = array( 'manage_options' ); 240 } 241 242 break; 243 244 /** bp component term ************************************************/ 245 case 'manage_bp_components' : 246 case 'edit_bp_components' : 247 case 'delete_bp_components' : 248 case 'bp_attachments_components_admin' : 249 250 // Admins can always edit 251 if ( user_can( $user_id, 'manage_options' ) ) { 252 $caps = array( 'manage_options' ); 253 } 254 255 break; 256 257 // This should be improved.. 258 case 'assign_bp_components' : 259 if ( is_user_logged_in() ) { 260 // In a network, most members has no role 261 $caps = array( 'exist' ); 262 } 263 break; 264 265 } 266 267 return apply_filters( 'bp_attachments_map_meta_caps', $caps, $cap, $user_id, $args ); 268 } 269 add_filter( 'bp_map_meta_caps', 'bp_attachments_map_meta_caps', 10, 4 ); 270 271 /** 272 * Specific function to check a user's capability 273 * 274 * @since BuddyPress (2.2.0) 275 * 276 * @uses BP_Attachments_Can to create the argument to check upon 277 * such as : 278 * - component 279 * - single item id 280 * - attachment id 281 */ 282 function bp_attachments_current_user_can( $capability = '', $args = false ) { 283 if ( ! empty( $args ) && is_array( $args ) ) 284 $args = new BP_Attachments_Can( $args ); 285 286 $blog_id = bp_get_root_blog_id(); 287 $args = array( $blog_id, $capability, $args ); 288 289 $retval = call_user_func_array( 'current_user_can_for_blog', $args ); 290 291 return (bool) apply_filters( 'bp_attachments_current_user_can', $retval, $args ); 292 } -
src/bp-attachments/bp-attachments-classes.php
diff --git src/bp-attachments/bp-attachments-classes.php src/bp-attachments/bp-attachments-classes.php index e69de29..588cab8 100644
1 <?php 2 /** 3 * Attachments Classes. 4 * 5 * @package BuddyPress 6 * @subpackage Attachments Classes 7 */ 8 9 // Exit if accessed directly 10 defined( 'ABSPATH' ) or exit; 11 12 /** 13 * Attachments Upload Class. 14 * 15 * This class is used to handle upload 16 * for components that are using the 17 * "bp_attachment"s post type 18 * 19 * @since BuddyPress (2.2.0) 20 */ 21 class BP_Attachments_Upload { 22 23 protected static $instance = null; 24 25 /** 26 * Construct the uploader. 27 * 28 * @since BuddyPress (2.2.0) 29 */ 30 public function __construct( $args = array() ) { 31 $this->setup_globals( $args ); 32 $this->includes(); 33 $this->setup_actions(); 34 $this->upload(); 35 $this->reset_actions(); 36 } 37 38 /** 39 * Starting point. 40 * 41 * @since BuddyPress (2.2.0) 42 */ 43 public static function start( $args = array() ) { 44 if ( empty( $args['action'] ) || empty( $args['file_id'] ) ) 45 return; 46 47 // If the single instance hasn't been set, set it now. 48 if ( null == self::$instance ) { 49 self::$instance = new self( $args ); 50 } 51 52 return self::$instance; 53 } 54 55 /** 56 * Define globals. 57 * 58 * @since BuddyPress (2.2.0) 59 */ 60 public function setup_globals( $args = array() ) { 61 62 $this->attachment_id = 0; 63 64 $r = bp_parse_args( $args, array( 65 'item_id' => 0, // what is the item id ? 66 'component' => '', // what is the component groups/members/messages ? 67 'item_type' => 'attachment', // attachment / avatar 68 'action' => 'bp_attachments_upload', // are specific strings needed ? 69 'file_id' => 'bp_attachment_file', // the name of the $_FILE to upload 70 ), 'attachments_uploader_args' ); 71 72 foreach( $r as $key => $value ) { 73 $this->{$key} = $value; 74 } 75 } 76 77 /** 78 * Include needed files. 79 * 80 * @since BuddyPress (2.2.0) 81 */ 82 private function includes() { 83 require_once( ABSPATH . '/wp-admin/includes/file.php' ); 84 require_once( ABSPATH . '/wp-admin/includes/media.php' ); 85 require_once( ABSPATH . '/wp-admin/includes/image.php' ); 86 } 87 88 /** 89 * Actions and filters to run 90 * before media_handle_upload() function is fired 91 * 92 * @since BuddyPress (2.2.0) 93 */ 94 private function setup_actions() { 95 // Filters 96 add_filter( 'upload_dir', array( $this, 'upload_dir' ), 10, 1 ); 97 add_filter( '_wp_relative_upload_path', array( $this, 'relative_path' ), 10, 2 ); 98 add_filter( 'wp_insert_attachment_data', array( $this, 'attachment_data' ), 10, 2 ); 99 // Actions 100 add_action( 'add_attachment', array( $this, 'attachment_metadata' ), 10, 1 ); 101 } 102 103 /** 104 * Upload! 105 * 106 * @since BuddyPress (2.2.0) 107 */ 108 private function upload() { 109 $attachment_data = array( 110 'post_type' => 'bp_attachment', 111 'context' => 'buddypress', 112 ); 113 114 // components are terms, an attachment can be attached to more than one component 115 if ( ! empty( $this->component ) ) { 116 $term = bp_attachments_get_component_term_id( $this->component ); 117 118 if ( ! empty( $term ) ) { 119 $attachment_data['tax_input'] = array( 'bp_component' => array( $term ) ); 120 } 121 } 122 123 $this->attachment_id = media_handle_upload( $this->file_id, 0, $attachment_data, array( 'action' => $this->action ) ); 124 } 125 126 /** 127 * Actions and filters to remove 128 * once media_handle_upload() function has done 129 * 130 * @since BuddyPress (2.2.0) 131 */ 132 private function reset_actions() { 133 // filters 134 remove_filter( 'upload_dir', array( $this, 'upload_dir' ), 10, 1 ); 135 remove_filter( '_wp_relative_upload_path', array( $this, 'relative_path' ), 10, 2 ); 136 remove_filter( 'wp_insert_attachment_data', array( $this, 'attachment_data' ), 10, 2 ); 137 // actions 138 remove_action( 'add_attachment', array( $this, 'attachment_metadata' ), 10, 1 ); 139 } 140 141 /** 142 * Filter upload dir 143 * 144 * @since BuddyPress (2.2.0) 145 * 146 * @todo handle private files using the post status 147 * of the "bp_attachment" post type 148 */ 149 public function upload_dir( $upload_data = array() ) { 150 $bp = buddypress(); 151 152 /** 153 * @todo private files! 154 * 155 * Using the post_status 156 */ 157 158 $path = bp_attachments_get_upload_dir( 'attachments_public_dir' ) . '/' . bp_loggedin_user_id(); 159 160 if ( ! file_exists( $path ) ) { 161 mkdir( $path ); 162 } 163 164 $url = bp_attachments_get_upload_dir( 'attachments_public_url' ) . '/' . bp_loggedin_user_id(); 165 166 $r = bp_parse_args( array( 167 'path' => $path, 168 'url' => $url, 169 'subdir' => false, 170 'basedir' => $path, 171 'baseurl' => $url, 172 ), $upload_data, 'attachments_upload_dir_args' ); 173 174 return $r; 175 } 176 177 /** 178 * Filter relative path 179 * 180 * @since BuddyPress (2.2.0) 181 * 182 * @todo handle private files using the post status 183 * of the "bp_attachment" post type 184 */ 185 public function relative_path( $new_path = '', $path = '' ) { 186 $bp = buddypress(); 187 188 /** 189 * @todo private files! 190 * 191 * Using the post_status 192 */ 193 194 if ( ! bp_attachments_get_upload_dir( 'attachments_public_dir' ) ) { 195 return $new_path; 196 } 197 198 if ( false !== strpos( $path, bp_attachments_get_upload_dir( 'attachments_public_dir' ) ) ) { 199 $new_path = str_replace( bp_attachments_get_upload_dir( 'attachments_dir' ), '', $path ); 200 $new_path = basename( bp_attachments_get_upload_dir( 'attachments_dir' ) ) . $new_path; 201 } 202 203 return $new_path; 204 } 205 206 /** 207 * Set the post type to bp_attachment 208 * instead of attachmnent 209 * 210 * @since BuddyPress (2.2.0) 211 */ 212 public function attachment_data( $data = array(), $object = array() ) { 213 if( 'buddypress' == $object['context'] ) { 214 $post_name = sanitize_title( $object['post_title'] ); 215 $post_name = wp_unique_post_slug( $post_name, 0, $data['post_status'], 'bp_attachment', $data['post_parent'] ); 216 $data = array_merge( $data, array( 217 'post_type' => 'bp_attachment', 218 'post_name' => $post_name 219 ) ); 220 } 221 222 return $data; 223 } 224 225 /** 226 * Finally add post meta to link to a single item id of the component 227 * 228 * for instance a group id. It's possible to add an attachment to more 229 * than one single item of the component 230 * 231 * @since BuddyPress (2.2.0) 232 */ 233 public function attachment_metadata( $attachment_id = 0 ) { 234 if ( empty( $attachment_id ) ) { 235 return; 236 } 237 238 if ( ! empty( $this->component ) && ! empty( $this->item_id ) ) { 239 add_post_meta( $attachment_id, "_bp_{$this->component}_id", $this->item_id ); 240 } 241 } 242 } 243 244 /** 245 * Attachments Browser Class. 246 * 247 * This class is used to create the 248 * "BP Attachments Editor" for attachments 249 * or Avatars 250 * 251 * @since BuddyPress (2.2.0) 252 */ 253 class BP_Attachments_Browser { 254 255 private static $settings = array(); 256 257 private function __construct() {} 258 259 /** 260 * Set the BP Attachments Editor settings 261 * 262 * @since BuddyPress (2.2.0) 263 */ 264 public static function set( $browser_id, $settings ) { 265 $set = bp_parse_args( $settings, array( 266 'item_id' => 0, // what is the item id ? 267 'component' => 'members', // what is the component groups/xprofile/members/messages ? 268 'item_type' => 'avatar', // avatar / image custom.. 269 'post_id' => 0, 270 'btn_caption' => __( 'Edit Avatar', 'buddypress' ), // the button caption 271 'btn_class' => 'bp_avatar', // the button class 272 'file_data_name' => 'bp_attachment_file', // the name of the $_FILE to upload 273 'multi_selection' => false, // allow multiple file upload ? 274 'action' => 'bp_attachments_upload', // the ajax action to deal with the file 275 'callback' => false, 276 'callback_id' => false, 277 ), 'attachments_browser_args' ); 278 279 self::$settings = array_merge( $set, array( 'bp_attachments_button_id' => '#' . $browser_id ) ); 280 return $set; 281 } 282 283 /** 284 * Display the button to launch the BP Attachments Editor 285 * 286 * @since BuddyPress (2.2.0) 287 */ 288 public static function browser( $browser_id, $settings = array() ) { 289 $set = self::set( $browser_id, $settings ); 290 291 $args = false; 292 if ( ! empty( $set['component'] ) && ! empty( $set['item_id'] ) ) 293 $args = wp_array_slice_assoc( $set, array( 'component', 'item_id' ) ); 294 295 if ( bp_attachments_current_user_can( 'publish_bp_attachments', $args ) ) { 296 // Need some extra attribute to the wrapper 297 add_filter( 'bp_button_attachments_create-' . $set['component'] . '-' . $set['item_type'], array( __CLASS__, 'btn_extra_attribute' ), 10, 4 ); 298 299 bp_button( array( 300 'id' => 'create-' . $set['component'] . '-' . $set['item_type'], 301 'component' => 'attachments', 302 'must_be_logged_in' => true, 303 'block_self' => false, 304 'wrapper_id' => $browser_id, 305 'wrapper_class' => $set['btn_class'], 306 'link_class' => 'add-' . $set['item_type'], 307 'link_href' => '#', 308 'link_title' => $set['btn_caption'], 309 'link_text' => $set['btn_caption'] 310 ) ); 311 312 remove_filter( 'bp_button_attachments_create-' . $set['component'] . '-' . $set['item_type'], array( __CLASS__, 'btn_extra_attribute' ), 10, 4 ); 313 314 // do not forget the fallback form if js is disabled or bp-media-editor out of service.. 315 if ( ! is_admin() ) { 316 add_action( 'bp_attachments_uploader_fallback', array( __CLASS__, 'fallback_uploader' ), 10 ); 317 } 318 } 319 320 self::browser_settings( $browser_id ); 321 } 322 323 /** 324 * This filter temporarly hide the button 325 * 326 * If no problem avoided the BP Attachments Editor to load 327 * then the javascript media-editor.js will show the button 328 * and remove the fallback uploader 329 * 330 * @since BuddyPress (2.2.0) 331 */ 332 public static function btn_extra_attribute( $contents = '', $button = null, $before = '', $after ='' ) { 333 $before = substr( $before, 0, -1 ); 334 $contents = str_replace( $before, $before .' style="display:none"', $contents ); 335 336 return $contents; 337 } 338 339 /** 340 * Fallback uploader when no-js 341 * 342 * @since BuddyPress (2.2.0) 343 */ 344 public static function fallback_uploader() { 345 $settings = self::$settings; 346 ?> 347 <form action="" method="post" id="attachment-upload-form" class="standard-form" enctype="multipart/form-data"> 348 <p id="attachment-upload"> 349 <input type="file" name="<?php echo esc_attr( $settings['file_data_name'] );?>" id="file" /> 350 <input type="submit" name="bp_attachment_upload" id="upload" value="<?php esc_attr_e( 'Upload', 'buddypress' ); ?>" /> 351 352 <?php if ( 'avatar' == $settings['item_type'] ) :?> 353 <input type="hidden" name="item_type" id="item-type" value="<?php echo esc_attr( $settings['item_type'] );?>" /> 354 <?php endif ;?> 355 356 <?php if ( ! empty( $settings['component'] ) ) :?> 357 <input type="hidden" name="component" id="component" value="<?php echo esc_attr( $settings['component'] );?>" /> 358 <?php endif ;?> 359 360 <?php if ( ! empty( $settings['item_id'] ) ) :?> 361 <input type="hidden" name="item_id" id="item-id" value="<?php echo esc_attr( $settings['item_id'] );?>" /> 362 <?php endif ;?> 363 364 <?php if ( ! empty( $settings['post_id'] ) ) :?> 365 <input type="hidden" name="post_id" id="post-id" value="<?php echo esc_attr( $settings['post_id'] );?>" /> 366 <?php endif ;?> 367 <input type="hidden" name="action" id="action" value="<?php echo esc_attr( $settings['action'] );?>" /> 368 <input type="hidden" name="file_data" id="file-data" value="<?php echo esc_attr( $settings['file_data_name'] );?>" /> 369 <?php wp_nonce_field( 'bp_attachments_upload', 'bp_attachments_upload_nonce' ); ?> 370 </p> 371 </form> 372 <?php 373 } 374 375 /** 376 * Filter the Media Editor strings, settings & params 377 * and enqueue the needed scripts 378 * 379 * @since BuddyPress (2.2.0) 380 */ 381 public static function browser_settings( $browser_id ) { 382 $settings = self::$settings; 383 384 $args = array(); 385 // Need to attach to a custom post types, let's use WordPress built in attachment features 386 if ( ! empty( self::$settings['post_id'] ) ) { 387 $args = array( 'post' => absint( self::$settings['post_id'] ) ); 388 } 389 390 // media view filters 391 add_filter( 'media_view_strings', array( __CLASS__, 'media_view_strings' ), 10, 1 ); 392 add_filter( 'media_view_settings', array( __CLASS__, 'media_view_settings' ), 10, 1 ); 393 394 // Plupload filters 395 add_filter( 'plupload_default_settings', array( __CLASS__, 'plupload_settings' ), 10, 1 ); 396 add_filter( 'plupload_default_params', array( __CLASS__, 'plupload_params' ), 10, 1 ); 397 398 // jcrop in case of avatar 399 if ( 'avatar' == self::$settings['item_type'] ) { 400 wp_enqueue_style( 'jcrop' ); 401 wp_enqueue_script( 'jcrop', array( 'jquery' ) ); 402 } 403 404 // Decide whether to load the dev version of the CSS and JavaScript 405 $min = defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ? '' : 'min.'; 406 407 // time to enqueue scripts 408 wp_enqueue_media( $args ); 409 wp_enqueue_script( 'bp-attachments-editor', buddypress()->plugin_url . "bp-attachments/js/script.{$min}js", array( 'media-editor' ), bp_get_version(), true ); 410 } 411 412 /** 413 * Custom strings for the BP Attachments Editor 414 * 415 * @since BuddyPress (2.2.0) 416 */ 417 public static function media_view_strings( $strings ) { 418 $bp_attachments_strings = array( 'bp_attachments' => array() ); 419 420 if ( 'avatar' == self::$settings['item_type'] ) { 421 $title = 'groups' == self::$settings['component'] ? __( 'Group Avatar', 'buddypress' ) : __( 'Avatar', 'buddypress' ); 422 $bp_attachments_strings = array( 'bp_attachments' => array( 423 'title' => $title, 424 'uploadtab' => __( 'Upload Avatar', 'buddypress' ), 425 'croptab' => __( 'Crop Avatar', 'buddypress' ), 426 ) ); 427 } 428 429 if ( 'attachment' == self::$settings['item_type'] ) { 430 $title = 'groups' == self::$settings['component'] ? __( 'Group Attachments', 'buddypress' ) : __( 'Attachments', 'buddypress' ); 431 $bp_attachments_strings = array( 'bp_attachments' => array( 432 'title' => $title, 433 'uploadtab' => __( 'Upload Attachments', 'buddypress' ), 434 'managetab' => __( 'Manage Attachments', 'buddypress' ), 435 ) ); 436 } 437 438 if ( ! self::$settings['multi_selection'] ) { 439 $bp_attachments_strings['bp_attachments'] = array_merge( 440 $bp_attachments_strings['bp_attachments'], 441 array( 'files_error' => __( 'One file at a time', 'buddypress' ) ) 442 ); 443 } 444 445 $bp_attachments_strings['bp_attachments'] = apply_filters( 'bp_attachments_strings', $bp_attachments_strings['bp_attachments'], self::$settings['bp_attachments_button_id'] ); 446 $bp_attachments_strings['bp_attachments'] = array_filter( $bp_attachments_strings['bp_attachments'] ); 447 448 $strings = array_merge( $strings, $bp_attachments_strings ); 449 450 return $strings; 451 } 452 453 /** 454 * Custom settings for the BP Attachments Editor 455 * 456 * @since BuddyPress (2.2.0) 457 */ 458 public static function media_view_settings( $settings ) { 459 $component = self::$settings['component']; 460 461 $settings['bp_attachments'] = array( 462 'item_id' => self::$settings['item_id'], 463 'item_type' => $component, 464 'button_id' => self::$settings['bp_attachments_button_id'], 465 ); 466 467 if ( 'avatar' == self::$settings['item_type'] ) { 468 469 switch ( $component ) { 470 case 'groups' : 471 $object = 'group'; 472 $avatar_dir = 'avatar_group_dir'; 473 break; 474 475 case 'blogs' : 476 $object = 'blog'; 477 $avatar_dir = 'avatar_blog_dir'; 478 break; 479 480 case 'xprofile' : 481 default : 482 $object = 'user'; 483 $avatar_dir = 'avatar_user_dir'; 484 break; 485 } 486 487 $settings['bp_attachments'] = array_merge( 488 $settings['bp_attachments'], 489 array( 490 'full_h' => bp_core_avatar_full_height(), 491 'full_w' => bp_core_avatar_full_width(), 492 'object' => $object, 493 'avatar_dir' => $avatar_dir, 494 ) 495 ); 496 } 497 498 return $settings; 499 } 500 501 /** 502 * Custom settings for plupload 503 * 504 * @since BuddyPress (2.2.0) 505 */ 506 public static function plupload_settings( $settings ) { 507 $settings['url'] = admin_url( 'admin-ajax.php' ); 508 $settings['file_data_name'] = self::$settings['file_data_name']; 509 $settings['multi_selection'] = self::$settings['multi_selection']; 510 511 return $settings; 512 } 513 514 /** 515 * Custom params for plupload 516 * 517 * @since BuddyPress (2.2.0) 518 */ 519 public static function plupload_params( $params ) { 520 $params = array( 521 'action' => self::$settings['action'], 522 'item_id' => self::$settings['item_id'], 523 'component' => self::$settings['component'], 524 'item_type' => self::$settings['item_type'], 525 'post_id' => self::$settings['post_id'], 526 '_bpnonce' => wp_create_nonce( 'bp_attachments_' . self::$settings['item_type'] ), 527 'callback' => self::$settings['callback'], 528 'callback_id' => self::$settings['callback_id'], 529 ); 530 531 return $params; 532 } 533 } 534 535 /** 536 * Attachments "CRUD" Class. 537 * 538 * Create is handled by the Upload Class 539 * 540 * @since BuddyPress (2.2.0) 541 */ 542 class BP_Attachments { 543 public $id; 544 public $user_id; 545 public $title; 546 public $description; 547 public $mime_type; 548 public $guid; 549 public $status; 550 public $item_ids; 551 public $components; 552 public $attachment; 553 554 /** 555 * Constructor. 556 * 557 * @since BuddyPress (2.2.0) 558 */ 559 function __construct( $id = 0 ){ 560 if ( ! empty( $id ) ) { 561 $this->id = $id; 562 $this->populate(); 563 } 564 } 565 566 /** 567 * request an item id 568 * 569 * @uses get_post() 570 * @uses wp_get_object_terms() 571 */ 572 public function populate() { 573 $this->attachment = get_post( $this->id ); 574 $this->user_id = $this->attachment->post_author; 575 $this->title = $this->attachment->post_title; 576 $this->description = $this->attachment->post_content; 577 $this->mime_type = $this->attachment->post_mime_type; 578 $this->guid = $this->attachment->guid; 579 $this->status = $this->attachment->post_status; 580 $this->components = wp_get_object_terms( $this->id, 'bp_component', array( 'fields' => 'all' ) ); 581 582 if ( ! empty( $this->components ) ) { 583 $this->item_ids = new stdClass(); 584 foreach( (array) $this->components as $component ) { 585 /** 586 * @todo transform ids into components slug 587 * bp_attachments_get_component_term_id( $component_id ) 588 * 589 * $component_id = bp_attachments_get_term_component_id( $component->term_id ); 590 * + Change $component->slug in favor of $component_id 591 */ 592 $this->item_ids->{$component->slug} = get_post_meta( $this->id, "_bp_{$component->slug}_id" ); 593 } 594 } 595 596 } 597 598 /** 599 * Update an attachment. 600 * 601 * @since BuddyPress (2.2.0) 602 * @todo changing from inherit (public) to private 603 * This will need to move files from one dir to another 604 */ 605 public function update() { 606 $this->id = apply_filters_ref_array( 'bp_attachments_id_before_update', array( $this->id, &$this ) ); 607 $this->user_id = apply_filters_ref_array( 'bp_attachments_user_id_before_update', array( $this->user_id, &$this ) ); 608 $this->title = apply_filters_ref_array( 'bp_attachments_title_before_update', array( $this->title, &$this ) ); 609 $this->description = apply_filters_ref_array( 'bp_attachments_description_before_update', array( $this->description, &$this ) ); 610 $this->status = apply_filters_ref_array( 'bp_attachments_status_before_update', array( $this->status, &$this ) ); 611 $this->item_ids = apply_filters_ref_array( 'bp_attachments_item_ids_before_update', array( $this->item_ids, &$this ) ); 612 $this->components = apply_filters_ref_array( 'bp_attachments_components_before_update', array( $this->components, &$this ) ); 613 614 // Use this, not the filters above 615 do_action_ref_array( 'bp_attachments_before_update', array( &$this ) ); 616 617 if ( ! $this->id || ! $this->user_id || ! $this->title ) 618 return false; 619 620 if ( ! $this->status ) 621 $this->status = 'inherit'; 622 623 /** 624 * If the status changed, we'll need to move files 625 */ 626 627 $update_args = array( 628 'ID' => $this->id, 629 'post_author' => $this->user_id, 630 'post_title' => $this->title, 631 'post_content' => $this->description, 632 'post_type' => 'bp_attachment', 633 'post_status' => $this->status 634 ); 635 636 $updated = wp_update_post( $update_args ); 637 638 $result = false; 639 640 if ( $updated ) { 641 $result = $this->title; 642 } 643 644 do_action_ref_array( 'bp_attachments_after_update', array( &$this ) ); 645 646 return $result; 647 } 648 649 /** 650 * The selection query 651 * 652 * @since BuddyPress (2.2.0) 653 * @param array $args arguments to customize the query 654 * @uses bp_parse_args 655 */ 656 public static function get( $args = array() ) { 657 658 $defaults = array( 659 'item_ids' => array(), // one or more item ids regarding the component (eg group_ids, message_ids ) 660 'component' => false, // groups / messages / blogs / xprofile... 661 'show_private' => false, // wether to include private attachment 662 'user_id' => false, // the author id of the attachment 663 'post_id' => false, 664 'per_page' => 20, 665 'page' => 1, 666 'search' => false, 667 'exclude' => false, // comma separated list or array of attachment ids. 668 'orderby' => 'modified', 669 'order' => 'DESC', 670 ); 671 672 $r = bp_parse_args( $args, $defaults, 'attachments_query_args' ); 673 674 $attachment_status = 'inherit'; 675 676 if ( ! empty( $r['show_private'] ) ) { 677 $attachment_status = array( 'inherit', 'private' ); 678 } 679 680 $query_args = array( 681 'post_status' => $attachment_status, 682 'post_type' => 'bp_attachment', 683 'posts_per_page' => $r['per_page'], 684 'paged' => $r['page'], 685 'orderby' => $r['orderby'], 686 'order' => $r['order'], 687 ); 688 689 if ( ! empty( $r['user_id'] ) ) { 690 $query_args['author'] = $r['user_id']; 691 } 692 693 if ( ! empty( $r['exclude'] ) ) { 694 if ( ! is_array( $r['exclude'] ) ) { 695 $r['exclude'] = explode( ',', $r['exclude'] ); 696 } 697 698 $query_args['post__not_in'] = $r['exclude']; 699 } 700 701 if ( ! empty( $r['post_id'] ) ) { 702 $query_args['post_parent'] = $r['post_id']; 703 } 704 705 if ( ! empty( $r['component'] ) ) { 706 /** 707 * @todo transform slugs into ids using 708 * bp_attachments_get_component_term_id( $component_id ) 709 * 710 * $component_ids = array_map( 'bp_attachments_get_component_term_id', $r['component'] ) 711 * + Change the tax query in favor of 712 * array( 713 * 'taxonomy' => 'bp_component', 714 * 'field' => 'term_id', 715 * 'terms' => $component_ids 716 * ) 717 */ 718 $query_args['tax_query'] = array( 719 array( 720 'taxonomy' => 'bp_component', 721 'field' => 'slug', 722 'terms' => $r['component'] 723 ) 724 ); 725 726 $component = $r['component']; 727 728 // component is defined, we can zoom on specific ids 729 if ( ! empty( $r['item_ids'] ) ) { 730 // We really want an array! 731 $item_ids = (array) $r['item_ids']; 732 733 $query_args['meta_query'] = array( 734 array( 735 'key' => "_bp_{$component}_id", 736 'value' => $item_ids, 737 'compare' => 'IN', 738 ) 739 ); 740 } 741 } 742 743 $attachments = new WP_Query( $query_args ); 744 745 return array( 'attachments' => $attachments->posts, 'total' => $attachments->found_posts ); 746 } 747 748 /** 749 * Return the number of attachments depending on the context. 750 * 751 * Used in BuddyPress nav (group & user) 752 * 753 * @since BuddyPress (2.2.0) 754 */ 755 public static function count( $args = array() ) { 756 global $wpdb; 757 758 $r = bp_parse_args( $args, array( 759 'status' => false, 760 'term_id' => false, 761 'user_id' => false, 762 'item_id' => false, 763 'term_slug' => false, 764 ) 765 , 'attachments_count_args' 766 ); 767 768 $sql = array(); 769 $detailed_count = array( 'total' => 0 ); 770 771 $sql['select'] = "SELECT COUNT( p.ID ) as count, p.post_status as status, t.term_taxonomy_id as term_id"; 772 $sql['from'] = "FROM {$wpdb->posts} p LEFT JOIN {$wpdb->term_relationships} t ON( p.ID = t.object_id )"; 773 $sql['where'] = array( $wpdb->prepare( "p.post_type = %s", 'bp_attachment' ) ); 774 $sql['groupby'] = array( 'p.post_status', 't.term_taxonomy_id' ); 775 776 if ( ! empty( $r['status'] ) ) { 777 $sql['where'][] = $wpdb->prepare( "p.post_status = %s", $r['status'] ); 778 } 779 780 if ( ! empty( $r['term_id'] ) ) { 781 $sql['where'][] = $wpdb->prepare( "t.term_taxonomy_id = %d", $r['term_id'] ); 782 } 783 784 if ( ! empty( $r['user_id'] ) ) { 785 $sql['where'][] = $wpdb->prepare( "p.post_author = %s", $r['user_id'] ); 786 } 787 788 if ( ! empty( $r['item_id'] ) && ! empty( $r['term_slug'] ) ) { 789 $sql['from'] .= " LEFT JOIN {$wpdb->postmeta} m ON ( p.ID = m.post_id )"; 790 $sql['where'][] = $wpdb->prepare( "m.meta_key = %s AND m.meta_value = %d", '_bp_' . $r['term_slug'] .'_id', $r['item_id'] ); 791 } 792 793 // join 794 $query = $sql['select'] . ' ' . $sql['from'] . ' WHERE ' . join( ' AND ', $sql['where'] ) . ' GROUP BY ' . join( ',', $sql['groupby'] ); 795 796 $results = $wpdb->get_results( $query ); 797 798 if ( empty( $results ) ) { 799 return $detailed_count; 800 } 801 802 foreach( $results as $result ) { 803 if ( empty( $result->count ) ) 804 continue; 805 806 $count = absint( $result->count ); 807 808 $detailed_count['total'] += $count; 809 810 if ( ! empty( $result->status ) ) { 811 // status 812 $detailed_count[ $result->status ] = empty( $detailed_count[ $result->status ] ) ? $count : absint( $detailed_count[ $result->status ] ) + $count; 813 814 // terms 815 if ( ! empty( $result->term_id ) ) { 816 $detailed_count[ $result->term_id ]['total'] = empty( $detailed_count[ $result->term_id ]['total'] ) ? $count : absint( $detailed_count[ $result->term_id ]['total'] ) + $count; 817 $detailed_count[ $result->term_id ][ $result->status ] = empty( $detailed_count[ $result->term_id ][ $result->status ] ) ? $count : absint( $detailed_count[ $result->term_id ][ $result->status ] ) + $count; 818 } 819 } 820 } 821 822 return $detailed_count; 823 } 824 825 /** 826 * Delete an attachment 827 * 828 * @since BuddyPress (2.2.0) 829 * @see wp_delete_attachment() this is an adapted version.. 830 */ 831 public static function delete( $attachment_id = 0 ) { 832 global $wpdb; 833 834 if( empty( $attachment_id ) ) { 835 return false; 836 } 837 838 if ( ! $attachment = $wpdb->get_row( $wpdb->prepare("SELECT * FROM {$wpdb->posts} WHERE ID = %d", $attachment_id ) ) ) { 839 return $attachment; 840 } 841 842 if ( 'bp_attachment' != $attachment->post_type ) { 843 return false; 844 } 845 846 $meta = wp_get_attachment_metadata( $attachment_id ); 847 $file = get_attached_file( $attachment_id ); 848 849 $intermediate_sizes = array(); 850 foreach ( get_intermediate_image_sizes() as $size ) { 851 if ( $intermediate = image_get_intermediate_size( $attachment_id, $size ) ) { 852 $intermediate_sizes[] = $intermediate; 853 } 854 } 855 856 if ( is_multisite() ) { 857 delete_transient( 'dirsize_cache' ); 858 } 859 860 do_action( 'bp_attachments_before_attachment_delete', $attachment_id ); 861 862 wp_delete_object_term_relationships( $attachment_id, get_object_taxonomies( $attachment->post_type ) ); 863 864 delete_metadata( 'post', null, '_thumbnail_id', $attachment_id, true ); // delete all for any posts. 865 866 $post_meta_ids = $wpdb->get_col( $wpdb->prepare( "SELECT meta_id FROM {$wpdb->postmeta} WHERE post_id = %d", $attachment_id ) ); 867 foreach ( $post_meta_ids as $mid ) { 868 delete_metadata_by_mid( 'post', $mid ); 869 } 870 871 $result = $wpdb->delete( $wpdb->posts, array( 'ID' => $attachment_id ) ); 872 if ( ! $result ) { 873 return false; 874 } 875 876 do_action( 'bp_attachments_after_attachment_db_delete', $attachment_id ); 877 878 $uploadpath = wp_upload_dir(); 879 880 if ( ! empty( $meta['thumb'] ) ) { 881 $thumbfile = str_replace( basename( $file), $meta['thumb'], $file ); 882 @ unlink( path_join( $uploadpath['basedir'], $thumbfile ) ); 883 } 884 885 foreach ( $intermediate_sizes as $intermediate ) { 886 @ unlink( path_join( $uploadpath['basedir'], $intermediate['path'] ) ); 887 } 888 889 if ( ! empty( $file ) ) { 890 @ unlink( $file ); 891 } 892 893 clean_post_cache( $attachment ); 894 895 do_action( 'bp_attachments_after_attachment_files_delete', $attachment_id ); 896 897 return $attachment; 898 } 899 } 900 901 /** 902 * Attachments Capability Class. 903 * 904 * This class is used to create the 905 * arguments to check in the capability 906 * mapping filter 907 * 908 * @since BuddyPress (2.2.0) 909 */ 910 class BP_Attachments_Can { 911 public function __construct( $args = array() ) { 912 if ( empty( $args ) ) { 913 return false; 914 } 915 916 $r = bp_parse_args( $args, array( 917 'component' => '', 918 'item_id' => '', 919 'attachment_id' => '' 920 ), 'attachments_can_args' ); 921 922 foreach( $r as $key => $value ) { 923 $this->{$key} = $value; 924 } 925 } 926 } -
src/bp-attachments/bp-attachments-cssjs.php
diff --git src/bp-attachments/bp-attachments-cssjs.php src/bp-attachments/bp-attachments-cssjs.php index e69de29..d182bf5 100644
1 <?php 2 /** 3 * Attachments CssJs. 4 * 5 * @package BuddyPress 6 * @subpackage Attachments CssJs 7 */ 8 9 // Exit if accessed directly 10 defined( 'ABSPATH' ) or exit; 11 12 /** 13 * Enqueues jCrop library and hooks BP's custom cropper JS. 14 */ 15 function bp_attachments_add_jquery_cropper() { 16 wp_enqueue_style( 'jcrop' ); 17 wp_enqueue_script( 'jcrop', array( 'jquery' ) ); 18 add_action( 'wp_head', 'bp_attachments_add_cropper_inline_js' ); 19 add_action( 'wp_head', 'bp_attachments_add_cropper_inline_css' ); 20 } 21 22 /** 23 * Output the inline JS needed for the cropper to work on a per-page basis. 24 */ 25 function bp_attachments_add_cropper_inline_js() { 26 27 // Bail if no image was uploaded 28 $image = apply_filters( 'bp_inline_cropper_image', getimagesize( bp_attachments_get_upload_dir() . buddypress()->avatar_admin->image->dir ) ); 29 if ( empty( $image ) ) { 30 return; 31 } 32 33 // Get avatar full width and height 34 $full_height = bp_core_avatar_full_height(); 35 $full_width = bp_core_avatar_full_width(); 36 37 // Calculate Aspect Ratio 38 if ( !empty( $full_height ) && ( $full_width != $full_height ) ) { 39 $aspect_ratio = $full_width / $full_height; 40 } else { 41 $aspect_ratio = 1; 42 } 43 44 // Default cropper coordinates 45 46 // Smaller than full-width: cropper defaults to entire image 47 if ( $image[0] < $full_width ) { 48 $crop_left = 0; 49 $crop_right = $image[0]; 50 51 // Less than 2x full-width: cropper defaults to full-width 52 } else if ( $image[0] < ( $full_width * 2 ) ) { 53 $padding_w = round( ( $image[0] - $full_width ) / 2 ); 54 $crop_left = $padding_w; 55 $crop_right = $image[0] - $padding_w; 56 57 // Larger than 2x full-width: cropper defaults to 1/2 image width 58 } else { 59 $crop_left = round( $image[0] / 4 ); 60 $crop_right = $image[0] - $crop_left; 61 } 62 63 // Smaller than full-height: cropper defaults to entire image 64 if ( $image[1] < $full_height ) { 65 $crop_top = 0; 66 $crop_bottom = $image[1]; 67 68 // Less than double full-height: cropper defaults to full-height 69 } else if ( $image[1] < ( $full_height * 2 ) ) { 70 $padding_h = round( ( $image[1] - $full_height ) / 2 ); 71 $crop_top = $padding_h; 72 $crop_bottom = $image[1] - $padding_h; 73 74 // Larger than 2x full-height: cropper defaults to 1/2 image height 75 } else { 76 $crop_top = round( $image[1] / 4 ); 77 $crop_bottom = $image[1] - $crop_top; 78 } 79 80 ?> 81 82 <script type="text/javascript"> 83 jQuery(window).load( function(){ 84 jQuery('#avatar-to-crop').Jcrop({ 85 onChange: showPreview, 86 onSelect: updateCoords, 87 aspectRatio: <?php echo (int) $aspect_ratio; ?>, 88 setSelect: [ <?php echo (int) $crop_left; ?>, <?php echo (int) $crop_top; ?>, <?php echo (int) $crop_right; ?>, <?php echo (int) $crop_bottom; ?> ] 89 }); 90 updateCoords({x: <?php echo (int) $crop_left; ?>, y: <?php echo (int) $crop_top; ?>, w: <?php echo (int) $crop_right; ?>, h: <?php echo (int) $crop_bottom; ?>}); 91 }); 92 93 function updateCoords(c) { 94 jQuery('#x').val(c.x); 95 jQuery('#y').val(c.y); 96 jQuery('#w').val(c.w); 97 jQuery('#h').val(c.h); 98 } 99 100 function showPreview(coords) { 101 if ( parseInt(coords.w) > 0 ) { 102 var fw = <?php echo (int) $full_width; ?>; 103 var fh = <?php echo (int) $full_height; ?>; 104 var rx = fw / coords.w; 105 var ry = fh / coords.h; 106 107 jQuery( '#avatar-crop-preview' ).css({ 108 width: Math.round(rx * <?php echo (int) $image[0]; ?>) + 'px', 109 height: Math.round(ry * <?php echo (int) $image[1]; ?>) + 'px', 110 marginLeft: '-' + Math.round(rx * coords.x) + 'px', 111 marginTop: '-' + Math.round(ry * coords.y) + 'px' 112 }); 113 } 114 } 115 </script> 116 117 <?php 118 } 119 120 /** 121 * Output the inline CSS for the BP image cropper. 122 * 123 * @package BuddyPress Core 124 */ 125 function bp_attachments_add_cropper_inline_css() { 126 ?> 127 128 <style type="text/css"> 129 .jcrop-holder { float: left; margin: 0 20px 20px 0; text-align: left; } 130 #avatar-crop-pane { width: <?php echo bp_core_avatar_full_width() ?>px; height: <?php echo bp_core_avatar_full_height() ?>px; overflow: hidden; } 131 #avatar-crop-submit { margin: 20px 0; } 132 .jcrop-holder img, 133 #avatar-crop-pane img, 134 #avatar-upload-form img, 135 #create-group-form img, 136 #group-settings-form img { border: none !important; max-width: none !important; } 137 </style> 138 139 <?php 140 } -
src/bp-attachments/bp-attachments-functions.php
diff --git src/bp-attachments/bp-attachments-functions.php src/bp-attachments/bp-attachments-functions.php index e69de29..0879b54 100644
1 <?php 2 /** 3 * Attachments functions 4 * 5 * @package BuddyPress 6 * @subpackage Attachments Functions 7 */ 8 9 // Exit if accessed directly 10 defined( 'ABSPATH' ) or exit; 11 12 /** 13 * Check avatar uploads settings 14 * 15 * @since BuddyPress (2.2.0) 16 */ 17 function bp_attachments_avatar_is_enabled() { 18 $bp = buddypress(); 19 20 if ( ! (int) $bp->site_options['bp-disable-avatar-uploads'] && $bp->avatar->show_avatars ) { 21 return true; 22 } 23 return false; 24 } 25 26 /** 27 * Create the upload directories 28 * 29 * @since BuddyPress (2.2.0) 30 * 31 * @uses is_multisite() 32 * @uses switch_to_blog() 33 * @uses bp_get_root_blog_id() 34 * @uses wp_upload_dir() 35 * @uses restore_current_blog() 36 * @uses wp_mkdir_p() 37 * @uses apply_filters() call 'bp_attachments_use_attachments_api' to create the dirs 38 * required by the BP Attachments API 39 * @return array list of upload urls and dirs 40 */ 41 function bp_attachments_set_upload_dirs() { 42 // We need to switch to the root blog on multisite installs 43 if ( is_multisite() ) { 44 switch_to_blog( bp_get_root_blog_id() ); 45 } 46 47 // Get upload directory information from current site 48 $upload_datas = wp_upload_dir(); 49 50 // Will bail if not switched 51 restore_current_blog(); 52 53 $bp_attachments_sub_dirs = array( 54 'avatar_user' => array( 'main' => 'avatars' ), 55 ); 56 57 if ( bp_is_active( 'groups' ) ) { 58 $bp_attachments_sub_dirs['avatar_group'] = array( 'main' => 'group-avatars' ); 59 } 60 61 if ( bp_is_active( 'blogs' ) ) { 62 $bp_attachments_sub_dirs['avatar_blog'] = array( 'main' => 'blog-avatars' ); 63 } 64 65 if ( buddypress()->attachments->use_api ) { 66 $bp_attachments_sub_dirs = array_merge( $bp_attachments_sub_dirs, array( 67 'attachments' => array( 'main' => 'bp-attachments', 'subs' => array( 'public', 'private' ) ), 68 ) ); 69 } 70 71 $bp_attachments_upload_data = array(); 72 $avatar_upload_data = array(); 73 74 if ( is_ssl() ) { 75 $upload_datas["baseurl"] = str_replace( 'http://', 'https://', $upload_datas["baseurl"] ); 76 } 77 78 foreach ( $bp_attachments_sub_dirs as $key => $dirs ) { 79 if ( false !== strpos( $key, 'avatar' ) ) { 80 $avatar_upload_data = array_merge( $avatar_upload_data, array( 81 $key . '_dir' => $upload_datas["basedir"] .'/' . $dirs['main'], 82 $key . '_url' => $upload_datas["baseurl"] .'/' . $dirs['main'], 83 ) ); 84 85 if ( defined( 'BP_AVATAR_UPLOAD_PATH' ) ) { 86 $avatar_upload_data[ $key . '_dir' ] = trailingslashit( BP_AVATAR_UPLOAD_PATH ) . $dirs['main']; 87 } 88 89 if ( defined( 'BP_AVATAR_URL' ) ) { 90 $avatar_upload_data[ $key . '_url' ] = trailingslashit( BP_AVATAR_URL ) . $dirs['main']; 91 } 92 93 } else if ( 'attachments' == $key ) { 94 // basedir and baseurl for BuddyPress attachments 95 $bp_attachments_upload_data = array( 96 $key . '_dir' => $upload_datas["basedir"] . '/' . $dirs['main'], 97 $key . '_url' => $upload_datas["baseurl"] . '/' . $dirs['main'], 98 ); 99 100 // Loop in subs 101 foreach ( $dirs['subs'] as $sub ) { 102 $bp_attachments_upload_data = array_merge( $bp_attachments_upload_data, array( 103 $key . '_' . $sub . '_dir' => $upload_datas["basedir"] . '/' . $dirs['main'] . '/' . $sub, 104 $key . '_' . $sub . '_url' => $upload_datas["baseurl"] . '/' . $dirs['main'] . '/' . $sub, 105 ) ); 106 } 107 } 108 } 109 110 // Append Avatar upload data 111 $bp_attachments_upload_data = array_merge( $avatar_upload_data, $bp_attachments_upload_data ); 112 113 // Loop in dirs to eventually create them if they do not exist 114 foreach ( $bp_attachments_upload_data as $key_upload_dir => $upload_dir ) { 115 116 if( ! file_exists( $upload_dir ) ) { 117 @wp_mkdir_p( $upload_dir ); 118 119 // Do additional actions (for instance create an .htaccess file for private dir) 120 do_action( 'bp_attachments_create_upload_dir', $key_upload_dir, $upload_dir ); 121 } 122 } 123 124 // Do backcompat for bp_core_get_upload_dir() 125 $bp_attachments_upload_data = array_merge( array( 126 'upload_path' => $upload_datas["basedir"], 127 'url' => $upload_datas["baseurl"], 128 ), $bp_attachments_upload_data ); 129 130 // finally returns upload_data 131 return $bp_attachments_upload_data; 132 } 133 134 /** 135 * Get the upload dir/url 136 * 137 * @since BuddyPress (2.2.0) 138 * 139 * @param string $type type dir/url to get 140 * @uses apply_filters() call 'bp_attachments_use_attachments_api' to get the dirs 141 * of the BP Attachments API 142 * @return string upload url or path 143 */ 144 function bp_attachments_get_upload_dir( $type = 'upload_path' ) { 145 $possible_matches = array( 146 'upload_path' => 1, 147 'url' => 1, 148 'avatar_user_dir' => 1, 149 'avatar_user_url' => 1, 150 ); 151 152 if ( bp_is_active( 'groups' ) ) { 153 $possible_matches = array_merge( $possible_matches, array( 154 'avatar_group_dir' => 1, 155 'avatar_group_url' => 1, 156 ) ); 157 } 158 159 if ( bp_is_active( 'blogs' ) ) { 160 $possible_matches = array_merge( $possible_matches, array( 161 'avatar_blog_dir' => 1, 162 'avatar_blog_url' => 1, 163 ) ); 164 } 165 166 if ( buddypress()->attachments->use_api ) { 167 $possible_matches = array_merge( $possible_matches, array( 168 'attachments_dir' => 1, 169 'attachments_url' => 1, 170 'attachments_public_dir' => 1, 171 'attachments_public_url' => 1, 172 'attachments_private_dir' => 1, 173 'attachments_private_url' => 1, 174 ) ); 175 } 176 177 // Only return upload datas 178 if ( empty( $possible_matches[ $type ] ) ) { 179 return false; 180 } 181 182 $hook_prefix = 'bp_attachments_get_'; 183 184 // Backcompat 185 if ( 'upload_path' == $type || 'url' == $type ) { 186 $hook_prefix = 'bp_core_avatar_'; 187 } 188 189 return apply_filters( $hook_prefix . $type , buddypress()->attachments->{$type} ); 190 } 191 192 /** 193 * Search for local avatar data and return an avatar object if any 194 * 195 * @since BuddyPress (2.2.0) 196 * 197 * @param object $avatar 198 * @return object the avatar object with local data if found 199 */ 200 function bp_attachments_avatar_local_data( $avatar = null ) { 201 if ( empty( $avatar->avatar_dir ) || ! bp_attachments_avatar_is_enabled() ) { 202 return $avatar; 203 } 204 205 // Set img URL and DIR based on prepopulated constants 206 $avatar->folder_dir = bp_attachments_get_upload_dir( $avatar->avatar_dir . '_dir' ); 207 208 if ( empty( $avatar->folder_dir ) ) { 209 $avatar->loc_path = trailingslashit( bp_attachments_get_upload_dir() ); 210 $avatar->loc_url = trailingslashit( bp_attachments_get_upload_dir( 'url' ) ); 211 212 $avatar->loc_dir = trailingslashit( $avatar->avatar_dir ); 213 $avatar->folder_url = apply_filters( 'bp_core_avatar_folder_url', ( $avatar->loc_url . $avatar->loc_dir . $avatar->item_id ), $avatar->item_id, $avatar->object, $avatar->avatar_dir ); 214 $avatar->folder_dir = apply_filters( 'bp_core_avatar_folder_dir', ( $avatar->loc_path . $avatar->loc_dir . $avatar->item_id ), $avatar->item_id, $avatar->object, $avatar->avatar_dir ); 215 } else { 216 $avatar->folder_dir = apply_filters( 'bp_core_avatar_folder_dir', trailingslashit( $avatar->folder_dir ) . $avatar->item_id, $avatar->item_id, $avatar->object, $avatar->avatar_dir ); 217 $avatar->folder_url = bp_attachments_get_upload_dir( $avatar->avatar_dir . '_url' ); 218 $avatar->folder_url = apply_filters( 'bp_core_avatar_folder_url', trailingslashit( $avatar->folder_url ) . $avatar->item_id, $avatar->item_id, $avatar->object, $avatar->avatar_dir ); 219 } 220 221 /** 222 * Look for uploaded avatar first. Use it if it exists. 223 * Set the file names to search for, to select the full size 224 * or thumbnail image. 225 */ 226 $avatar_size = ( 'full' == $avatar->type ) ? '-bpfull' : '-bpthumb'; 227 $legacy_user_avatar_name = ( 'full' == $avatar->type ) ? '-avatar2' : '-avatar1'; 228 $legacy_group_avatar_name = ( 'full' == $avatar->type ) ? '-groupavatar-full' : '-groupavatar-thumb'; 229 230 // Check for directory 231 if ( file_exists( $avatar->folder_dir ) ) { 232 233 // Open directory 234 if ( $av_dir = opendir( $avatar->folder_dir ) ) { 235 236 // Stash files in an array once to check for one that matches 237 $avatar_files = array(); 238 while ( false !== ( $avatar_file = readdir( $av_dir ) ) ) { 239 // Only add files to the array (skip directories) 240 if ( 2 < strlen( $avatar_file ) ) { 241 $avatar_files[] = $avatar_file; 242 } 243 } 244 245 // Check for array 246 if ( 0 < count( $avatar_files ) ) { 247 248 // Check for current avatar 249 foreach( $avatar_files as $key => $value ) { 250 if ( strpos ( $value, $avatar_size )!== false ) { 251 $avatar->url = $avatar->folder_url . '/' . $avatar_files[$key]; 252 } 253 } 254 255 // Legacy avatar check 256 if ( empty( $avatar->url ) ) { 257 foreach( $avatar_files as $key => $value ) { 258 if ( strpos ( $value, $legacy_user_avatar_name )!== false ) { 259 $avatar->url = $avatar->folder_url . '/' . $avatar_files[$key]; 260 } 261 } 262 263 // Legacy group avatar check 264 if ( empty( $avatar->url ) ) { 265 foreach( $avatar_files as $key => $value ) { 266 if ( strpos ( $value, $legacy_group_avatar_name )!== false ) { 267 $avatar->url = $avatar->folder_url . '/' . $avatar_files[$key]; 268 } 269 } 270 } 271 } 272 } 273 } 274 } 275 276 return $avatar; 277 } 278 add_filter( 'bp_core_avatar_local_data', 'bp_attachments_avatar_local_data', 10, 1 ); 279 280 /** 281 * Delete an existing avatar. 282 * 283 * @since BuddyPress (2.2.0) 284 * 285 * @param array $args { 286 * Array of function parameters. 287 * @type bool|int $item_id ID of the item whose avatar you're deleting. 288 * Defaults to the current item of type $object. 289 * @type string $object Object type of the item whose avatar you're 290 * deleting. 'user', 'group', 'blog', or custom. Default: 'user'. 291 * @type bool|string $avatar_dir Subdirectory where avatar is located. 292 * Default: false, which falls back on the default location 293 * corresponding to the $object. 294 * } 295 * @return bool True on success, false on failure. 296 */ 297 function bp_attachments_delete_existing_avatar( $args = '' ) { 298 299 $defaults = array( 300 'item_id' => false, 301 'object' => 'user', // user OR group OR blog OR custom type (if you use filters) 302 'avatar_dir' => false 303 ); 304 305 $r = wp_parse_args( $args, $defaults ); 306 307 if ( empty( $r['item_id'] ) ) { 308 if ( 'user' == $r['object'] ) { 309 $r['item_id'] = bp_displayed_user_id(); 310 } else if ( 'group' == $r['object'] ) { 311 $r['item_id'] = buddypress()->groups->current_group->id; 312 } else if ( 'blog' == $r['object'] ) { 313 $r['item_id'] = get_current_blog_id(); 314 } 315 316 $r['item_id'] = apply_filters( 'bp_core_avatar_item_id', $r['item_id'], $r['object'] ); 317 318 if ( ! $r['item_id'] ) { 319 return false; 320 } 321 } 322 323 if ( empty( $r['avatar_dir'] ) ) { 324 if ( 'user' == $r['object'] ) { 325 $r['avatar_dir'] = 'avatar_user_dir'; 326 } else if ( 'group' == $r['object'] ) { 327 $r['avatar_dir'] = 'avatar_group_dir'; 328 } else if ( 'blog' == $r['object'] ) { 329 $r['avatar_dir'] = 'avatar_blog_dir'; 330 } 331 332 $r['avatar_dir'] = apply_filters( 'bp_core_avatar_dir', $r['avatar_dir'], $r['object'] ); 333 334 if ( ! $r['avatar_dir'] ) { 335 return false; 336 } 337 } 338 339 $avatar_folder_dir = bp_attachments_get_upload_dir( $r['avatar_dir'] ); 340 341 // Backcompat 342 if ( empty( $avatar_folder_dir ) ) { 343 $avatar_folder_dir = bp_attachments_get_upload_dir() . '/' . $r['avatar_dir']; 344 } 345 346 $avatar_folder_dir .= '/' . $r['item_id']; 347 348 $avatar_folder_dir = apply_filters( 'bp_core_avatar_folder_dir', $avatar_folder_dir, $r['item_id'], $r['object'], $r['avatar_dir'] ); 349 350 if ( ! file_exists( $avatar_folder_dir ) ) { 351 return false; 352 } 353 354 if ( $av_dir = opendir( $avatar_folder_dir ) ) { 355 while ( false !== ( $avatar_file = readdir($av_dir) ) ) { 356 if ( ( preg_match( "/-bpfull/", $avatar_file ) || preg_match( "/-bpthumb/", $avatar_file ) ) && '.' != $avatar_file && '..' != $avatar_file ) { 357 @unlink( $avatar_folder_dir . '/' . $avatar_file ); 358 } 359 } 360 } 361 closedir($av_dir); 362 363 @rmdir( $avatar_folder_dir ); 364 365 do_action( 'bp_core_delete_existing_avatar', $args ); 366 367 return true; 368 } 369 370 /** 371 * Setup the avatar upload directory for a user. 372 * 373 * @since BuddyPress (2.2.0) 374 * 375 * @package BuddyPress Core 376 * 377 * @param string $directory The root directory name. Optional. 378 * @param int $user_id The user ID. Optional. 379 * 380 * @return array() Array containing the path, URL, and other helpful settings. 381 */ 382 function bp_attachments_xprofile_avatar_upload_dir( $directory = 'avatar_user_dir', $user_id = 0 ) { 383 $bp = buddypress(); 384 385 // Use displayed user if no user ID was passed 386 if ( empty( $user_id ) ) { 387 // Default 388 $user_id = bp_displayed_user_id(); 389 390 // In Profile administration screen displayed user id is not set 391 if ( ! empty( $bp->avatar_admin->image->item_id ) && 'xprofile' == $bp->avatar_admin->image->component ) { 392 $user_id = $bp->avatar_admin->image->item_id; 393 } 394 } 395 396 // Failsafe against accidentally nooped $directory parameter 397 if ( empty( $directory ) ) { 398 $directory = 'avatar_user_dir'; 399 } 400 401 $avatar_folder_dir = bp_attachments_get_upload_dir( $directory ); 402 403 // Backcompat 404 if ( empty( $avatar_folder_dir ) ) { 405 $avatar_folder_dir = bp_attachments_get_upload_dir() . '/' . $directory; 406 } 407 408 $path = $avatar_folder_dir . '/' . $user_id; 409 $newbdir = $path; 410 411 if ( ! file_exists( $path ) ) { 412 @wp_mkdir_p( $path ); 413 } 414 415 // Backcompat 416 if ( 'avatar_user_dir' != $directory ) { 417 $newurl = bp_attachments_get_upload_dir( 'url' ) . '/' . $directory. '/' . $user_id; 418 } else { 419 $newurl = bp_attachments_get_upload_dir( 'avatar_user_url' ) . '/' . $user_id; 420 } 421 422 $newburl = $newurl; 423 424 return apply_filters( 'xprofile_avatar_upload_dir', array( 425 'path' => $path, 426 'url' => $newurl, 427 'subdir' => false, 428 'basedir' => $newbdir, 429 'baseurl' => $newburl, 430 'error' => false 431 ) ); 432 } 433 434 /** 435 * Generate the avatar upload directory path for a given group. 436 * 437 * @since BuddyPress (2.2.0) 438 * 439 * @param int $group_id Optional. ID of the group. Default: ID of the 440 * current group. 441 * @return string 442 */ 443 function bp_attachments_groups_avatar_upload_dir( $group_id = 0 ) { 444 $bp = buddypress(); 445 446 // Bail if groups component is not active 447 if ( ! bp_is_active( 'groups' ) ) { 448 return false; 449 } 450 451 if ( empty( $group_id ) ) { 452 $group_id = bp_get_current_group_id(); 453 454 // In Group administration screen current group id is not set 455 if ( ! empty( $bp->avatar_admin->image->item_id ) && 'groups' == $bp->avatar_admin->image->component ) { 456 $group_id = $bp->avatar_admin->image->item_id; 457 } 458 } 459 460 $path = bp_attachments_get_upload_dir( 'avatar_group_dir' ) . '/' . $group_id; 461 $newbdir = $path; 462 463 if ( ! file_exists( $path ) ) { 464 @wp_mkdir_p( $path ); 465 } 466 467 $newurl = bp_attachments_get_upload_dir( 'avatar_group_url' ) . '/' . $group_id; 468 $newburl = $newurl; 469 470 return apply_filters( 'groups_avatar_upload_dir', array( 471 'path' => $path, 472 'url' => $newurl, 473 'subdir' => false, 474 'basedir' => $newbdir, 475 'baseurl' => $newburl, 476 'error' => false 477 ) ); 478 } 479 480 /** 481 * Get the avatar storage directory for use during registration. 482 * 483 * @since BuddyPress (2.2.0) 484 * 485 * @return string|bool Directory path on success, false on failure. 486 */ 487 function bp_attachments_signup_avatar_upload_dir() { 488 $bp = buddypress(); 489 490 if ( empty( $bp->signup->avatar_dir ) ) { 491 return false; 492 } 493 494 $path = bp_attachments_get_upload_dir( 'avatar_user_dir' ) . '/signups/' . $bp->signup->avatar_dir; 495 $newbdir = $path; 496 497 if ( ! file_exists( $path ) ) { 498 @wp_mkdir_p( $path ); 499 } 500 501 $newurl = bp_attachments_get_upload_dir( 'avatar_user_url' ) . '/signups/' . $bp->signup->avatar_dir; 502 $newburl = $newurl; 503 504 return apply_filters( 'bp_core_signup_avatar_upload_dir', array( 505 'path' => $path, 506 'url' => $newurl, 507 'subdir' => false, 508 'basedir' => $newbdir, 509 'baseurl' => $newburl, 510 'error' => false 511 ) ); 512 } 513 514 /** 515 * Prepare an avatar to be displayed in the BP Attachments Editor 516 * 517 * @since BuddyPress (2.2.0) 518 */ 519 function bp_attachments_prepare_avatar_for_js( $avatar = null ) { 520 if ( empty( $avatar ) ) { 521 return; 522 } 523 524 $response = array( 525 'id' => $avatar->item_id, 526 'title' => $avatar->name, 527 'component' => $avatar->component, 528 'filename' => wp_basename( $avatar->dir ), 529 'url' => $avatar->url, 530 'path' => $avatar->dir, 531 'width' => $avatar->width, 532 'height' => $avatar->height, 533 'src' => $avatar->src, 534 ); 535 536 return apply_filters( 'bp_attachments_prepare_avatar_for_js', $response, $avatar ); 537 } 538 539 /** 540 * Handle avatar uploading. 541 * 542 * The functions starts off by checking that the file has been uploaded 543 * properly using bp_attachments_check_avatar_upload(). It then checks that the file 544 * size is within limits, and that it has an accepted file extension (jpg, gif, 545 * png). If everything checks out, crop the image and move it to its real 546 * location. 547 * 548 * @since BuddyPress (2.2.0) 549 * 550 * @see bp_attachments_check_avatar_upload() 551 * @see bp_attachments_check_avatar_type() 552 * 553 * @param array $file The appropriate entry the from $_FILES superglobal. 554 * @param string $component the component for the avatar (xprofile, groups,blogs..). 555 * @return string json object or url to the uploaded avatar 556 */ 557 function bp_attachments_avatar_handle_upload( $file, $component, $item_id = 0, $do_js = false ) { 558 $bp = buddypress(); 559 560 /*** 561 * You may want to hook into this filter if you want to override this function. 562 * Make sure you return false. 563 */ 564 if ( ! apply_filters( 'bp_core_pre_avatar_handle_upload', true, $file, $component . '_avatar_upload_dir', $component, $item_id, $do_js ) ) { 565 return true; 566 } 567 568 /** 569 * Map Dirs for backcompat 570 */ 571 if ( empty( $bp->active_components[ $component ] ) ) { 572 $dirs = array( 573 'group-avatars' => $bp->groups->id, 574 'blog-avatars' => $bp->blogs->id, 575 'avatars/signup' => 'signup', 576 'avatars' => $bp->profile->id, 577 ); 578 579 if ( ! empty( $dirs[ $component ] ) ) { 580 $component = $dirs[ $component ]; 581 } else if ( ! empty( $bp->signup->avatar_dir ) ) { 582 $component = 'signup'; 583 } 584 } 585 586 require_once( ABSPATH . '/wp-admin/includes/file.php' ); 587 588 $uploadErrors = array( 589 0 => __( 'The image was uploaded successfully', 'buddypress' ), 590 1 => __( 'The image exceeds the maximum allowed file size of: ', 'buddypress' ) . size_format( bp_attachments_avatar_original_max_filesize() ), 591 2 => __( 'The image exceeds the maximum allowed file size of: ', 'buddypress' ) . size_format( bp_attachments_avatar_original_max_filesize() ), 592 3 => __( 'The uploaded file was only partially uploaded.', 'buddypress' ), 593 4 => __( 'The image was not uploaded.', 'buddypress' ), 594 6 => __( 'Missing a temporary folder.', 'buddypress' ) 595 ); 596 597 if ( ! bp_attachments_check_avatar_upload( $file ) ) { 598 return new WP_Error( 'upload_error', sprintf( __( 'Your upload failed, please try again. Error was: %s', 'buddypress' ), $uploadErrors[$file['file']['error']] ), $file ); 599 } 600 601 if ( ! bp_attachments_check_avatar_size( $file ) ) { 602 return new WP_Error( 'upload_error', sprintf( __( 'The file you uploaded is too big. Please upload a file under %s', 'buddypress' ), size_format( bp_attachments_avatar_original_max_filesize() ) ), $file ); 603 } 604 605 if ( ! bp_attachments_check_avatar_type( $file ) ) { 606 return new WP_Error( 'upload_error', __( 'Please upload only JPG, GIF or PNG photos.', 'buddypress' ), $file ); 607 } 608 609 if ( ! isset( $bp->avatar_admin ) ) { 610 $bp->avatar_admin = new stdClass(); 611 } 612 613 // Set the item id and the component of the uploaded avatar 614 $bp->avatar_admin->image = (object) array( 615 'item_id' => $item_id, 616 'component' => $component, 617 ); 618 619 if ( ! is_callable( "bp_attachments_{$component}_avatar_upload_dir" ) ) { 620 return new WP_Error( 'upload_error', sprintf( __( 'Avatar cannot be uploaded for the component: %s. Please contact the administrator.', 'buddypress' ), $component ), $file ); 621 } 622 623 // Filter the upload location 624 add_filter( 'upload_dir', "bp_attachments_{$component}_avatar_upload_dir", 10, 0 ); 625 626 $bp->avatar_admin->original = wp_handle_upload( $file['file'], array( 'action'=> 'bp_avatar_upload' ) ); 627 628 // Remove the upload_dir filter, so that other upload URLs on the page 629 // don't break 630 remove_filter( 'upload_dir',"bp_attachments_{$component}_avatar_upload_dir", 10, 0 ); 631 632 // Move the file to the correct upload location. 633 if ( ! empty( $bp->avatar_admin->original['error'] ) ) { 634 return new WP_Error( 'upload_error', sprintf( __( 'Upload Failed! Error was: %s', 'buddypress' ), $bp->avatar_admin->original['error'] ), $file ); 635 } 636 637 // Get image size 638 $size = @getimagesize( $bp->avatar_admin->original['file'] ); 639 $error = false; 640 641 // Check image size and shrink if too large 642 if ( $size[0] > bp_attachments_avatar_original_max_width() ) { 643 $editor = wp_get_image_editor( $bp->avatar_admin->original['file'] ); 644 645 if ( ! is_wp_error( $editor ) ) { 646 $editor->set_quality( 100 ); 647 648 $resized = $editor->resize( bp_attachments_avatar_original_max_width(), bp_attachments_avatar_original_max_width(), false ); 649 if ( ! is_wp_error( $resized ) ) { 650 $thumb = $editor->save( $editor->generate_filename() ); 651 } else { 652 $error = $resized; 653 } 654 655 // Check for thumbnail creation errors 656 if ( false === $error && is_wp_error( $thumb ) ) { 657 $error = $thumb; 658 } 659 660 // Thumbnail is good so proceed 661 if ( false === $error ) { 662 $bp->avatar_admin->resized = $thumb; 663 } 664 665 } else { 666 $error = $editor; 667 } 668 669 if ( false !== $error ) { 670 return $error; 671 } 672 } 673 674 // We only want to handle one image after resize. 675 if ( empty( $bp->avatar_admin->resized ) ) { 676 $bp->avatar_admin->image->dir = str_replace( bp_attachments_get_upload_dir(), '', $bp->avatar_admin->original['file'] ); 677 } else { 678 $size = @getimagesize( $bp->avatar_admin->resized['path'] ); 679 $bp->avatar_admin->image->dir = str_replace( bp_attachments_get_upload_dir(), '', $bp->avatar_admin->resized['path'] ); 680 @unlink( $bp->avatar_admin->original['file'] ); 681 } 682 683 // Check for WP_Error on what should be an image 684 if ( is_wp_error( $bp->avatar_admin->image->dir ) ) { 685 $bp->avatar_admin->image->dir->add_data( sprintf( __( 'Upload failed! Error was: %s', 'buddypress' ), $bp->avatar_admin->image->dir->get_error_message() ) ); 686 return $bp->avatar_admin->image->dir; 687 } 688 689 // If the uploaded image is smaller than the "full" dimensions, throw 690 // a warning 691 $uploaded_image = @getimagesize( bp_attachments_get_upload_dir() . $bp->avatar_admin->image->dir ); 692 $full_width = bp_core_avatar_full_width(); 693 $full_height = bp_core_avatar_full_height(); 694 695 if ( isset( $uploaded_image[0] ) && $uploaded_image[0] < $full_width || $uploaded_image[1] < $full_height ) { 696 // Remove the image that doesn't match the minimum dimensions. 697 @unlink( $bp->avatar_admin->original['file'] ); 698 699 // Return the error 700 return new WP_Error( 'upload_error', sprintf( __( 'You have selected an image that is smaller than recommended. For best results, upload a picture larger than %d x %d pixels.', 'buddypress' ), $full_width, $full_height ), $file ); 701 } 702 703 // Set the name of the file 704 $name = $file['file']['name']; 705 $name_parts = pathinfo( $name ); 706 $name = trim( substr( $name, 0, - ( 1 + strlen( $name_parts['extension'] ) ) ) ); 707 $bp->avatar_admin->image->name = $name; 708 709 if ( ! empty( $size ) ) { 710 $bp->avatar_admin->image->width = $size[0]; 711 $bp->avatar_admin->image->height = $size[1]; 712 } 713 714 // Set the url value for the image 715 $bp->avatar_admin->image->url = bp_attachments_get_upload_dir( 'url' ) . $bp->avatar_admin->image->dir; 716 $bp->avatar_admin->image->src = apply_filters( 'bp_get_avatar_to_crop_src', str_replace( WP_CONTENT_DIR, '', $bp->avatar_admin->image->dir ) ); 717 718 if ( ! empty( $do_js ) ) { 719 return bp_attachments_prepare_avatar_for_js( $bp->avatar_admin->image ); 720 } else { 721 return $bp->avatar_admin->image->src; 722 } 723 } 724 725 /** 726 * Reset the week parameter of the WordPress main query if needed 727 * 728 * When cropping an avatar, a $_POST['w'] var is sent, setting the 'week' 729 * paramater of the WordPress main query to this posted var. To avoid 730 * notices, we need to make sure this 'week' query var is reset to 0 731 * 732 * @since BuddyPress (2.2.0) 733 * 734 * @param WP_Quert $posts_query the main query object 735 * @uses bp_is_group_create() 736 * @uses bp_is_group_admin_page() 737 * @uses bp_is_group_admin_screen() to check for a group admin screen 738 * @uses bp_action_variable() to check for the group's avatar creation step 739 * @uses bp_is_user_change_avatar() to check for the user's change profile screen 740 */ 741 function bp_attachments_avatar_reset_query( $posts_query = null ) { 742 $reset_w = false; 743 744 // Group's avatar edit screen 745 if ( bp_is_group_admin_page() ) { 746 $reset_w = bp_is_group_admin_screen( 'group-avatar' ); 747 748 // Group's avatar create screen 749 } else if ( bp_is_group_create() ) { 750 /** 751 * we can't use bp_get_groups_current_create_step() 752 * as it's not set yet 753 */ 754 $reset_w = 'group-avatar' === bp_action_variable( 1 ); 755 756 // User's change avatar screen 757 } else { 758 $reset_w = bp_is_user_change_avatar(); 759 } 760 761 // A user or a group is cropping an avatar 762 if ( true === $reset_w && isset( $_POST['avatar-crop-submit'] ) ) { 763 $posts_query->set( 'w', 0 ); 764 } 765 } 766 add_action( 'bp_parse_query', 'bp_attachments_avatar_reset_query', 10, 1 ); 767 768 /** 769 * Crop an uploaded avatar. 770 * 771 * $args has the following parameters: 772 * object - What component the avatar is for, e.g. "user" 773 * avatar_dir The absolute path to the avatar 774 * item_id - Item ID 775 * original_file - The absolute path to the original avatar file 776 * crop_w - Crop width 777 * crop_h - Crop height 778 * crop_x - The horizontal starting point of the crop 779 * crop_y - The vertical starting point of the crop 780 * 781 * @since BuddyPress (2.2.0) 782 * 783 * @param array $args { 784 * Array of function parameters. 785 * @type string $object Object type of the item whose avatar you're 786 * handling. 'user', 'group', 'blog', or custom. Default: 'user'. 787 * @type string $avatar_dir Subdirectory where avatar should be stored. 788 * Default: 'avatars'. 789 * @type bool|int $item_id ID of the item that the avatar belongs to. 790 * @type bool|string $original_file Absolute papth to the original avatar 791 * file. 792 * @type int $crop_w Crop width. Default: the global 'full' avatar width, 793 * as retrieved by bp_core_avatar_full_width(). 794 * @type int $crop_h Crop height. Default: the global 'full' avatar height, 795 * as retrieved by bp_core_avatar_full_height(). 796 * @type int $crop_x The horizontal starting point of the crop. Default: 0. 797 * @type int $crop_y The vertical starting point of the crop. Default: 0. 798 * } 799 * @return bool True on success, false on failure. 800 */ 801 function bp_attachments_avatar_handle_crop( $args = '' ) { 802 803 $r = wp_parse_args( $args, array( 804 'object' => 'user', 805 'avatar_dir' => 'avatar_user_dir', 806 'item_id' => false, 807 'original_file' => false, 808 'crop_w' => bp_core_avatar_full_width(), 809 'crop_h' => bp_core_avatar_full_height(), 810 'crop_x' => 0, 811 'crop_y' => 0 812 ) ); 813 814 /*** 815 * You may want to hook into this filter if you want to override this function. 816 * Make sure you return false. 817 */ 818 if ( ! apply_filters( 'bp_core_pre_avatar_handle_crop', true, $r ) ) { 819 return true; 820 } 821 822 if ( empty( $r['original_file'] ) ) { 823 return false; 824 } 825 826 $original_file = bp_attachments_get_upload_dir() . $r['original_file']; 827 828 if ( ! file_exists( $original_file ) ) { 829 return false; 830 } 831 832 $avatar_folder_dir = bp_attachments_get_upload_dir( $r['avatar_dir'] ); 833 834 // Backcompat 835 if ( empty( $avatar_folder_dir ) ) { 836 $avatar_folder_dir = bp_attachments_get_upload_dir() . '/' . $r['avatar_dir']; 837 } 838 839 if ( empty( $r['item_id'] ) ) { 840 $avatar_folder_dir = apply_filters( 'bp_core_avatar_folder_dir', dirname( $original_file ), $r['item_id'], $r['object'], $r['avatar_dir'] ); 841 } else { 842 $avatar_folder_dir = apply_filters( 'bp_core_avatar_folder_dir', trailingslashit( $avatar_folder_dir ) . $r['item_id'], $r['item_id'], $r['object'], $r['avatar_dir'] ); 843 } 844 845 if ( ! file_exists( $avatar_folder_dir ) ) { 846 return false; 847 } 848 849 require_once( ABSPATH . '/wp-admin/includes/image.php' ); 850 require_once( ABSPATH . '/wp-admin/includes/file.php' ); 851 852 // Delete the existing avatar files for the object 853 $existing_avatar = bp_core_fetch_avatar( array( 854 'object' => $r['object'], 855 'item_id' => $r['item_id'], 856 'html' => false, 857 ) ); 858 859 if ( ! empty( $existing_avatar ) ) { 860 // Check that the new avatar doesn't have the same name as the 861 // old one before deleting 862 $upload_dir = wp_upload_dir(); 863 $existing_avatar_path = str_replace( $upload_dir['baseurl'], '', $existing_avatar ); 864 $new_avatar_path = str_replace( $upload_dir['basedir'], '', $original_file ); 865 866 if ( $existing_avatar_path !== $new_avatar_path ) { 867 bp_attachments_delete_existing_avatar( array( 'object' => $r['object'], 'item_id' => $r['item_id'], 'avatar_path' => $avatar_folder_dir ) ); 868 } 869 } 870 871 // Make sure we at least have a width and height for cropping 872 if ( empty( $r['crop_w'] ) ) { 873 $r['crop_w'] = bp_core_avatar_full_width(); 874 } 875 876 if ( empty( $r['crop_h'] ) ) { 877 $r['crop_h'] = bp_core_avatar_full_height(); 878 } 879 880 // Get the file extension 881 $data = @getimagesize( $original_file ); 882 $ext = $data['mime'] == 'image/png' ? 'png' : 'jpg'; 883 884 // Set the full and thumb filenames 885 $full_filename = wp_hash( $original_file . time() ) . '-bpfull.' . $ext; 886 $thumb_filename = wp_hash( $original_file . time() ) . '-bpthumb.' . $ext; 887 888 // Crop the image 889 $full_cropped = wp_crop_image( $original_file, (int) $r['crop_x'], (int) $r['crop_y'], (int) $r['crop_w'], (int) $r['crop_h'], bp_core_avatar_full_width(), bp_core_avatar_full_height(), false, $avatar_folder_dir . '/' . $full_filename ); 890 $thumb_cropped = wp_crop_image( $original_file, (int) $r['crop_x'], (int) $r['crop_y'], (int) $r['crop_w'], (int) $r['crop_h'], bp_core_avatar_thumb_width(), bp_core_avatar_thumb_height(), false, $avatar_folder_dir . '/' . $thumb_filename ); 891 892 // Check for errors 893 if ( empty( $full_cropped ) || empty( $thumb_cropped ) || is_wp_error( $full_cropped ) || is_wp_error( $thumb_cropped ) ) { 894 return false; 895 } 896 897 // Remove the original 898 @unlink( $original_file ); 899 900 return true; 901 } 902 903 /** 904 * Is the current avatar upload error-free? 905 * 906 * @since BuddyPress (2.2.0) 907 * 908 * @param array $file The $_FILES array. 909 * @return bool True if no errors are found. False if there are errors. 910 */ 911 function bp_attachments_check_avatar_upload( $file ) { 912 if ( isset( $file['error'] ) && $file['error'] ) 913 return false; 914 915 return true; 916 } 917 918 /** 919 * Is the file size of the current avatar upload permitted? 920 * 921 * @since BuddyPress (2.2.0) 922 * 923 * @param array $file The $_FILES array. 924 * @return bool True if the avatar is under the size limit, otherwise false. 925 */ 926 function bp_attachments_check_avatar_size( $file ) { 927 if ( $file['file']['size'] > bp_attachments_avatar_original_max_filesize() ) 928 return false; 929 930 return true; 931 } 932 933 /** 934 * Does the current avatar upload have an allowed file type? 935 * 936 * Permitted file types are JPG, GIF and PNG. 937 * 938 * @since BuddyPress (2.2.0) 939 * 940 * @param array $file The $_FILES array. 941 * @return bool True if the file extension is permitted, otherwise false. 942 */ 943 function bp_attachments_check_avatar_type( $file ) { 944 if ( ( !empty( $file['file']['type'] ) && !preg_match('/(jpe?g|gif|png)$/i', $file['file']['type'] ) ) || !preg_match( '/(jpe?g|gif|png)$/i', $file['file']['name'] ) ) 945 return false; 946 947 return true; 948 } 949 950 /** 951 * Get the max width for original avatar uploads. 952 * 953 * @since BuddyPress (2.2.0) 954 * 955 * @return int The max width for original avatar uploads. 956 */ 957 function bp_attachments_avatar_original_max_width() { 958 return apply_filters( 'bp_core_avatar_original_max_width', (int) buddypress()->avatar->original_max_width ); 959 } 960 961 /** 962 * Get the max filesize for original avatar uploads. 963 * 964 * @since BuddyPress (2.2.0) 965 * 966 * @return int The max filesize for original avatar uploads. 967 */ 968 function bp_attachments_avatar_original_max_filesize() { 969 return apply_filters( 'bp_core_avatar_original_max_filesize', (int) buddypress()->avatar->original_max_filesize ); 970 } 971 972 /** Attachments **************************************************************/ 973 974 /** 975 * Get the term id for a given component 976 * 977 * Using term slugs, there's a possibility $bp->{component}->id != term slug 978 * 979 * @since BuddyPress (2.2.0) 980 * 981 * @param string $component_id the component id 982 * @return int the term id 983 */ 984 function bp_attachments_get_component_term_id( $component_id = '' ) { 985 $bp = buddypress(); 986 987 if ( ! empty( $bp->attachments->component_terms[ $component_id ] ) ) { 988 return (int) $bp->attachments->component_terms[ $component_id ]; 989 } 990 991 return false; 992 } 993 994 /** 995 * Get the component id for a given term 996 * 997 * Using term slugs, there's a possibility $bp->{component}->id != term slug 998 * 999 * @since BuddyPress (2.2.0) 1000 * 1001 * @param int $term_id the term id 1002 * @return string the component id 1003 */ 1004 function bp_attachments_get_term_component_id( $term_id = 0 ) { 1005 $bp = buddypress(); 1006 1007 $terms_component = array_flip( $bp->attachments->component_terms ); 1008 1009 if ( ! empty( $terms_component[ $term_id ] ) ) { 1010 return $terms_component[ $term_id ]; 1011 } 1012 1013 return false; 1014 } 1015 1016 /** 1017 * Get a single attachment 1018 * 1019 * @since BuddyPress (2.2.0) 1020 * 1021 * @param integer $attachment_id 1022 * @return BP_Attachments 1023 */ 1024 function bp_attachments_get_attachment( $attachment_id = 0 ) { 1025 if ( empty( $attachment_id ) ) 1026 return false; 1027 1028 $attachment = new BP_Attachments( $attachment_id ); 1029 1030 return apply_filters( 'bp_attachments_get_attachment', $attachment ); 1031 } 1032 1033 /** 1034 * Get a single attachment 1035 * 1036 * @since BuddyPress (2.2.0) 1037 * 1038 * @param array $args 1039 * @return array of BP_Attachments 1040 */ 1041 function bp_attachments_get_attachments( $args = array() ) { 1042 1043 $defaults = array( 1044 'item_ids' => array(), // one or more item ids regarding the component (eg group_ids, message_ids ) 1045 'component' => false, // groups / messages / blogs / xprofile... 1046 'show_private' => false, // wether to include private attachment 1047 'user_id' => false, // the author id of the attachment 1048 'per_page' => 20, 1049 'page' => 1, 1050 'search' => false, 1051 'exclude' => false, // comma separated list or array of attachment ids. 1052 'orderby' => 'ID', 1053 'order' => 'DESC', 1054 ); 1055 1056 $r = bp_parse_args( $args, $defaults, 'attachments_get_args' ); 1057 1058 $attachments = wp_cache_get( 'bp_attachments_attachments', 'bp' ); 1059 1060 if ( empty( $attachments ) ) { 1061 $attachments = BP_Attachments::get( array( 1062 'item_ids' => (array) $r['item_ids'], 1063 'component' => $r['component'], 1064 'show_private' => (bool) $r['show_private'], 1065 'user_id' => $r['user_id'], 1066 'per_page' => $r['per_page'], 1067 'page' => $r['page'], 1068 'search' => $r['search'], 1069 'exclude' => $r['exclude'], 1070 'orderby' => $r['orderby'], 1071 'order' => $r['order'], 1072 ) ); 1073 1074 wp_cache_set( 'bp_attachments_attachments', $attachments, 'bp' ); 1075 } 1076 1077 return apply_filters_ref_array( 'bp_attachments_get_attachments', array( &$attachments, &$r ) ); 1078 } 1079 1080 /** 1081 * Upload attachment 1082 * 1083 * @since BuddyPress (2.2.0) 1084 * 1085 * @param array $args 1086 * @return int the id of the created attachment 1087 */ 1088 function bp_attachments_handle_upload( $args = array() ) { 1089 1090 $r = bp_parse_args( $args, array( 1091 'item_id' => 0, 1092 'component' => '', 1093 'item_type' => 'attachment', 1094 'action' => 'bp_attachments_upload', 1095 'file_id' => 'bp_attachment_file', 1096 ), 'attachments_handle_upload_args' ); 1097 1098 $attachment_upload = BP_Attachments_Upload::start( $r ); 1099 1100 return $attachment_upload->attachment_id; 1101 } 1102 1103 /** 1104 * Delete attachment 1105 * 1106 * @since BuddyPress (2.2.0) 1107 * 1108 * @param int the id of the attachment 1109 * @return mixed false/title of the deleted attachment 1110 */ 1111 function bp_attachments_delete_attachment( $attachment_id = 0 ) { 1112 if ( empty( $attachment_id ) ) { 1113 return false; 1114 } 1115 1116 if ( ! bp_attachments_current_user_can( 'delete_bp_attachment', $attachment_id ) ) { 1117 return false; 1118 } 1119 1120 $deleted = BP_Attachments::delete( $attachment_id ); 1121 1122 if ( ! empty( $deleted->post_title ) ) { 1123 return $deleted->post_title; 1124 } else { 1125 return false; 1126 } 1127 } 1128 1129 /** 1130 * Delete attachment 1131 * 1132 * @since BuddyPress (2.2.0) 1133 * 1134 * @param array $args 1135 * @return mixed false/title of the updated attachment 1136 */ 1137 function bp_attachments_update_attachment( $args = array() ) { 1138 $r = bp_parse_args( $args, array( 1139 'id' => 0, 1140 'title' => '', 1141 'description' => '', 1142 'privacy' => 'inherit', 1143 'component' => array(), 1144 'terms' => '', 1145 'ajax' => false 1146 ), 'attachments_update_attachment_args' ); 1147 1148 if ( empty( $r['id'] ) ) { 1149 return false; 1150 } 1151 1152 if ( ! bp_attachments_current_user_can( 'edit_bp_attachment', $r['id'] ) ) { 1153 return false; 1154 } 1155 1156 $attachment = new BP_Attachments( $r['id'] ); 1157 1158 if ( empty( $attachment ) ) { 1159 return false; 1160 } 1161 1162 if ( empty( $r['title'] ) ) { 1163 $r['title'] = $attachment->title; 1164 } 1165 1166 $attachment->title = $r['title']; 1167 $attachment->description = $r['description']; 1168 $attachment->status = $r['privacy']; 1169 1170 if ( empty( $r['ajax'] ) ) { 1171 1172 $prev_item_ids = ! empty( $attachment->item_ids ) ? $attachment->item_ids : false; 1173 1174 if ( ! empty( $r['terms'] ) ) { 1175 $terms = explode( ',', $r['terms'] ); 1176 // Let's handle the item ids here 1177 foreach ( $terms as $key => $term ) { 1178 if ( empty( $r['component'][ $term ] ) ) { 1179 // delete all ! 1180 delete_post_meta( $id, "_bp_{$term}_id" ); 1181 unset( $terms[ $key ] ); 1182 } else { 1183 if ( empty( $prev_item_ids->{$term} ) ) { 1184 foreach( $r['component'][ $term ] as $item_id ) 1185 add_post_meta( $id, "_bp_{$term}_id", $item_id ); 1186 1187 } else { 1188 $to_delete = array_diff( $prev_item_ids->{$term}, $r['component'][ $term ] ); 1189 $to_add = array_diff( $r['component'][ $term ], $prev_item_ids->{$term} ); 1190 1191 if ( ! empty( $to_delete ) ){ 1192 // Delete item ids 1193 foreach ( $to_delete as $item_id ) { 1194 delete_post_meta( $id, "_bp_{$term}_id", $item_id ); 1195 } 1196 } 1197 1198 if ( ! empty( $to_add ) ){ 1199 // Delete item ids 1200 foreach ( $to_add as $item_id ) { 1201 add_post_meta( $id, "_bp_{$term}_id", $item_id ); 1202 } 1203 } 1204 } 1205 } 1206 } 1207 1208 if ( empty( $terms ) ) { 1209 $terms = null; 1210 } 1211 1212 /** 1213 * @todo transform slugs into ids using 1214 * bp_attachments_get_component_term_id( $component_id ) 1215 */ 1216 wp_set_object_terms( $r['id'], $terms, 'bp_component' ); 1217 1218 } else { 1219 wp_set_object_terms( $r['id'], null, 'bp_component' ); 1220 } 1221 1222 } 1223 1224 return $attachment->update(); 1225 } 1226 1227 /** 1228 * Launch the BP Attachments Editor 1229 * 1230 * @since BuddyPress (2.2.0) 1231 */ 1232 function bp_attachments_browser( $browser_id, $settings = array() ) { 1233 BP_Attachments_Browser::browser( $browser_id, $settings ); 1234 } 1235 1236 /** 1237 * Retrieve the URL for an attachment. 1238 * 1239 * This is an adapted version of wp_get_attachment_url() 1240 * 1241 * @since BuddyPress (2.2.0) 1242 * 1243 * @param int $post_id Attachment ID. 1244 * @return string 1245 */ 1246 function bp_attachments_get_attachment_url( $post_id = 0 ) { 1247 $post_id = (int) $post_id; 1248 $post = get_post( $post_id ); 1249 1250 if ( empty( $post ) ) { 1251 return false; 1252 } 1253 1254 if ( 'bp_attachment' != $post->post_type ) { 1255 return false; 1256 } 1257 1258 $url = ''; 1259 // Get attached file 1260 $file = get_post_meta( $post->ID, '_wp_attached_file', true ); 1261 if ( ! empty( $file ) ) { 1262 $uploads = wp_upload_dir(); 1263 1264 // Get upload directory 1265 if ( ! empty( $uploads ) && false === $uploads['error'] ) { 1266 1267 // Check that the upload base exists in the file location 1268 if ( 0 === strpos( $file, $uploads['basedir'] ) ) { 1269 // replace file location with url location 1270 $url = str_replace( $uploads['basedir'], $uploads['baseurl'], $file ); 1271 } else if ( false !== strpos( $file, 'wp-content/uploads' ) ) { 1272 $url = $uploads['baseurl'] . substr( $file, strpos($file, 'wp-content/uploads') + 18 ); 1273 1274 // Its a newly uploaded file, therefor $file is relative to the basedir. 1275 } else { 1276 $url = $uploads['baseurl'] . "/$file"; 1277 } 1278 } 1279 } 1280 1281 //If any of the above options failed, Fallback on the GUID 1282 if ( empty( $url ) ) { 1283 $url = get_the_guid( $post->ID ); 1284 } 1285 1286 $url = apply_filters( 'bp_attachments_get_attachment_url', $url, $post->ID ); 1287 1288 if ( empty( $url ) ) { 1289 return false; 1290 } 1291 1292 return $url; 1293 } 1294 1295 /** 1296 * Custom filter for WordPress image_downsize 1297 * 1298 * Use it before and after wp_get_attachment_image() 1299 * 1300 * @see bp_attachments_get_attachment_image() 1301 * 1302 * @since BuddyPress (2.2.0) 1303 */ 1304 function bp_attachments_image_downsize( $output = '', $id = 0, $size = 'medium' ) { 1305 $img_url = bp_attachments_get_attachment_url( $id ); 1306 $meta = wp_get_attachment_metadata($id); 1307 $width = $height = 0; 1308 $is_intermediate = false; 1309 $img_url_basename = wp_basename($img_url); 1310 1311 // try for a new style intermediate size 1312 if ( $intermediate = image_get_intermediate_size($id, $size) ) { 1313 $img_url = str_replace($img_url_basename, $intermediate['file'], $img_url); 1314 $width = $intermediate['width']; 1315 $height = $intermediate['height']; 1316 $is_intermediate = true; 1317 } 1318 elseif ( $size == 'thumbnail' ) { 1319 // fall back to the old thumbnail 1320 if ( ($thumb_file = wp_get_attachment_thumb_file($id)) && $info = getimagesize($thumb_file) ) { 1321 $img_url = str_replace($img_url_basename, wp_basename($thumb_file), $img_url); 1322 $width = $info[0]; 1323 $height = $info[1]; 1324 $is_intermediate = true; 1325 } 1326 } 1327 if ( !$width && !$height && isset( $meta['width'], $meta['height'] ) ) { 1328 // any other type: use the real image 1329 $width = $meta['width']; 1330 $height = $meta['height']; 1331 } 1332 1333 if ( $img_url) { 1334 // we have the actual image size, but might need to further constrain it if content_width is narrower 1335 list( $width, $height ) = image_constrain_size_for_editor( $width, $height, $size ); 1336 1337 return array( $img_url, $width, $height, $is_intermediate ); 1338 } 1339 return false; 1340 } 1341 1342 /** 1343 * Get an HTML img element representing an image attachment 1344 * 1345 * @since BuddyPress (2.2.0) 1346 * 1347 * @param int $attachment_id Image attachment ID. 1348 * @param string|array $size Optional. Default 'thumbnail'. 1349 * @param bool $icon Optional. Whether it is an icon. Default false. 1350 * @param string|array $attr Optional. Attributes for the image markup. Default empty string. 1351 * @uses wp_get_attachment_image() 1352 * @return string HTML img element or empty string on failure. 1353 */ 1354 function bp_attachments_get_attachment_image( $attachment_id, $size = 'thumbnail', $icon = false, $attr = '' ) { 1355 // Temporarly filter image_downsize() 1356 add_filter( 'image_downsize', 'bp_attachments_image_downsize', 10, 3 ); 1357 1358 $attachment_image = wp_get_attachment_image( $attachment_id, $size, $icon, $attr ); 1359 1360 // Reset image_downsize() 1361 remove_filter( 'image_downsize', 'bp_attachments_image_downsize', 10, 3 ); 1362 1363 return apply_filters( 'bp_attachments_get_attachment_image', $attachment_image, $attachment_id, $size, $icon, $attr ); 1364 } 1365 1366 /** 1367 * Prepare an attachment to be displayed in the BP Attachments Editor 1368 * 1369 * this is an adapted copy of wp_prepare_attachment_for_js() 1370 * 1371 * @since BuddyPress (2.2.0) 1372 */ 1373 function bp_attachments_prepare_attachment_for_js( $attachment ) { 1374 if ( empty( $attachment ) ) { 1375 return; 1376 } 1377 1378 if ( ! is_a( $attachment, 'WP_Post' ) && is_numeric( $attachment ) ) { 1379 $get_attachment = bp_attachments_get_attachment( $attachment ); 1380 1381 if ( ! empty( $get_attachment->attachment ) ) { 1382 $attachment = $get_attachment->attachment; 1383 } 1384 } 1385 1386 if ( 'bp_attachment' != $attachment->post_type ) { 1387 return; 1388 } 1389 1390 $meta = wp_get_attachment_metadata( $attachment->ID ); 1391 if ( false !== strpos( $attachment->post_mime_type, '/' ) ) { 1392 list( $type, $subtype ) = explode( '/', $attachment->post_mime_type ); 1393 } else { 1394 list( $type, $subtype ) = array( $attachment->post_mime_type, '' ); 1395 } 1396 1397 $attachment_url = bp_attachments_get_attachment_url( $attachment->ID ); 1398 1399 $response = array( 1400 'id' => $attachment->ID, 1401 'title' => $attachment->post_title, 1402 'filename' => wp_basename( $attachment->guid ), 1403 'url' => $attachment_url, 1404 'link' => get_attachment_link( $attachment->ID ), 1405 'alt' => get_post_meta( $attachment->ID, '_wp_attachment_image_alt', true ), 1406 'author' => $attachment->post_author, 1407 'description' => $attachment->post_content, 1408 'caption' => $attachment->post_excerpt, 1409 'name' => $attachment->post_name, 1410 'status' => $attachment->post_status, 1411 'uploadedTo' => $attachment->post_parent, 1412 'date' => strtotime( $attachment->post_date_gmt ) * 1000, 1413 'modified' => strtotime( $attachment->post_modified_gmt ) * 1000, 1414 'menuOrder' => $attachment->menu_order, 1415 'mime' => $attachment->post_mime_type, 1416 'type' => $type, 1417 'subtype' => $subtype, 1418 'icon' => wp_mime_type_icon( $attachment->ID ), 1419 'dateFormatted' => mysql2date( get_option('date_format'), $attachment->post_date ), 1420 'nonces' => array( 1421 'update' => false, 1422 'delete' => false, 1423 ), 1424 'editLink' => false, 1425 ); 1426 1427 if ( current_user_can( 'edit_bp_attachment', $attachment->ID ) ) { 1428 $response['nonces']['update'] = wp_create_nonce( 'update_bp_attachment_' . $attachment->ID ); 1429 $response['editLink'] = bp_attachments_get_edit_link( $attachment->ID, $attachment->post_author ); 1430 } 1431 1432 if ( current_user_can( 'delete_bp_attachment', $attachment->ID ) ) { 1433 $response['nonces']['delete'] = wp_create_nonce( 'delete_bp_attachment_' . $attachment->ID ); 1434 } 1435 1436 if ( $meta && 'image' === $type ) { 1437 $sizes = array(); 1438 /** This filter is documented in wp-admin/includes/media.php */ 1439 $possible_sizes = apply_filters( 'image_size_names_choose', array( 1440 'thumbnail' => __('Thumbnail'), 1441 'medium' => __('Medium'), 1442 'large' => __('Large'), 1443 'full' => __('Full Size'), 1444 ) ); 1445 unset( $possible_sizes['full'] ); 1446 1447 // Loop through all potential sizes that may be chosen. Try to do this with some efficiency. 1448 // First: run the image_downsize filter. If it returns something, we can use its data. 1449 // If the filter does not return something, then image_downsize() is just an expensive 1450 // way to check the image metadata, which we do second. 1451 foreach ( $possible_sizes as $size => $label ) { 1452 if ( $downsize = apply_filters( 'image_downsize', false, $attachment->ID, $size ) ) { 1453 if ( ! $downsize[3] ) { 1454 continue; 1455 } 1456 1457 $sizes[ $size ] = array( 1458 'height' => $downsize[2], 1459 'width' => $downsize[1], 1460 'url' => $downsize[0], 1461 'orientation' => $downsize[2] > $downsize[1] ? 'portrait' : 'landscape', 1462 ); 1463 } elseif ( isset( $meta['sizes'][ $size ] ) ) { 1464 if ( ! isset( $base_url ) ) { 1465 $base_url = str_replace( wp_basename( $attachment_url ), '', $attachment_url ); 1466 } 1467 1468 // Nothing from the filter, so consult image metadata if we have it. 1469 $size_meta = $meta['sizes'][ $size ]; 1470 1471 // We have the actual image size, but might need to further constrain it if content_width is narrower. 1472 // Thumbnail, medium, and full sizes are also checked against the site's height/width options. 1473 list( $width, $height ) = image_constrain_size_for_editor( $size_meta['width'], $size_meta['height'], $size, 'edit' ); 1474 1475 $sizes[ $size ] = array( 1476 'height' => $height, 1477 'width' => $width, 1478 'url' => $base_url . $size_meta['file'], 1479 'orientation' => $height > $width ? 'portrait' : 'landscape', 1480 ); 1481 } 1482 } 1483 1484 $sizes['full'] = array( 'url' => $attachment_url ); 1485 1486 if ( isset( $meta['height'], $meta['width'] ) ) { 1487 $sizes['full']['height'] = $meta['height']; 1488 $sizes['full']['width'] = $meta['width']; 1489 $sizes['full']['orientation'] = $meta['height'] > $meta['width'] ? 'portrait' : 'landscape'; 1490 } 1491 1492 $response = array_merge( $response, array( 'sizes' => $sizes ), $sizes['full'] ); 1493 } elseif ( $meta && 'video' === $type ) { 1494 if ( isset( $meta['width'] ) ) { 1495 $response['width'] = (int) $meta['width']; 1496 } 1497 1498 if ( isset( $meta['height'] ) ) { 1499 $response['height'] = (int) $meta['height']; 1500 } 1501 } 1502 1503 if ( $meta && ( 'audio' === $type || 'video' === $type ) ) { 1504 if ( isset( $meta['length_formatted'] ) ) { 1505 $response['fileLength'] = $meta['length_formatted']; 1506 } 1507 } 1508 1509 return apply_filters( 'bp_attachments_prepare_attachment_for_js', $response, $attachment, $meta ); 1510 } 1511 1512 /** 1513 * Build the edit link of an attachement 1514 * 1515 * @since BuddyPress (2.2.0) 1516 */ 1517 function bp_attachments_get_edit_link( $attachment_id = 0, $user_id = 0 ) { 1518 if ( empty( $attachment_id ) ) { 1519 return false; 1520 } 1521 1522 if ( empty( $user_id ) ) { 1523 $user_id = bp_loggedin_user_id(); 1524 } 1525 1526 $edit_link = trailingslashit( bp_core_get_user_domain( $user_id ) . buddypress()->attachments->slug ); 1527 $edit_link = add_query_arg( array( 'attachment' => $attachment_id, 'action' => 'edit' ), $edit_link ); 1528 1529 return apply_filters( 'bp_attachments_get_edit_link', $edit_link, $attachment_id, $user_id ); 1530 } 1531 1532 /** 1533 * Build the delete link of an attachement 1534 * 1535 * @since BuddyPress (2.2.0) 1536 */ 1537 function bp_attachments_get_delete_link( $attachment_id = 0, $user_id = 0 ) { 1538 if ( empty( $attachment_id ) ) { 1539 return false; 1540 } 1541 1542 if ( empty( $user_id ) ) { 1543 $user_id = bp_loggedin_user_id(); 1544 } 1545 1546 $delete_link = trailingslashit( bp_core_get_user_domain( $user_id ) . buddypress()->attachments->slug ); 1547 $delete_link = add_query_arg( array( 'attachment' => $attachment_id, 'action' => 'delete' ), $delete_link ); 1548 1549 return apply_filters( 'bp_attachments_get_delete_link', $delete_link, $attachment_id, $user_id ); 1550 } -
src/bp-attachments/bp-attachments-loader.php
diff --git src/bp-attachments/bp-attachments-loader.php src/bp-attachments/bp-attachments-loader.php index e69de29..e37024f 100644
1 <?php 2 /** 3 * Attachments Component. 4 * 5 * A media component, for others ! 6 * 7 * @package BuddyPress 8 * @subpackage Attachments 9 */ 10 11 // Exit if accessed directly 12 defined( 'ABSPATH' ) or exit; 13 /** 14 * Main Attachments Class. 15 * 16 * @since BuddyPress (2.2.0) 17 */ 18 class BP_Attachments_Component extends BP_Component { 19 20 /** 21 * If true enables upload dirs, post type & taxonomy 22 * 23 * @var bool 24 */ 25 public $use_api; 26 27 /** 28 * Start the attachments component setup process. 29 * 30 * @since BuddyPress (2.2.0) 31 */ 32 public function __construct() { 33 parent::start( 34 'attachments', 35 __( 'Attachments', 'buddypress' ), 36 buddypress()->plugin_dir 37 ); 38 39 // Filter here to enable Attachments API 40 $this->use_api = apply_filters( 'bp_attachments_use_attachments_api', false ); 41 42 // Launch specific hooks 43 $this->actions(); 44 } 45 46 /** 47 * Include component files. 48 * 49 * @since BuddyPress (2.2.0) 50 */ 51 public function includes( $includes = array() ) { 52 // Files to include 53 $includes = array( 54 'cssjs', 55 'actions', 56 'filters', 57 'screens', 58 'caps', 59 'classes', 60 'ajax', 61 'functions', 62 ); 63 64 if ( is_admin() ) { 65 $includes[] = 'admin'; 66 } 67 68 parent::includes( $includes ); 69 } 70 71 /** 72 * Set up component global variables. 73 * 74 * @since BuddyPress (2.2.0) 75 */ 76 public function setup_globals( $args = array() ) { 77 $bp = buddypress(); 78 79 // Define a slug, if necessary 80 if ( ! defined( 'BP_ATTACHMENTS_SLUG' ) ) { 81 define( 'BP_ATTACHMENTS_SLUG', $this->id ); 82 } 83 84 // All globals for attachments component. 85 $args = array( 86 'slug' => BP_ATTACHMENTS_SLUG, 87 'has_directory' => false, 88 'notification_callback' => 'bp_attachments_format_notifications', 89 ); 90 91 parent::setup_globals( $args ); 92 } 93 94 /** 95 * Run specific actions to create post type/taxonomy... 96 * 97 * @since BuddyPress (2.2.0) 98 */ 99 public function actions() { 100 // register upload datas 101 add_action( 'bp_' . $this->id . '_setup_globals', array( $this, 'register_upload_datas' ), 10 ); 102 103 // Edit user's profile photo nav 104 add_action( 'bp_xprofile_setup_nav', array( $this, 'xprofile_setup_nav' ) ); 105 add_filter( 'bp_xprofile_admin_nav', array( $this, 'xprofile_setup_nav' ), 10, 1 ); 106 107 // Group's avatar creation step 108 add_filter( 'groups_create_group_steps', array( $this, 'groups_setup_avatar_step' ), 10, 1 ); 109 add_action( 'bp_groups_setup_nav', array( $this, 'groups_setup_manage_tab' ) ); 110 111 if ( ! empty( $this->use_api ) && get_current_blog_id() == bp_get_root_blog_id() ) { 112 // register bp_attachments post type 113 add_action( 'bp_init', array( $this, 'register_post_types' ) ); 114 // register bp_component taxonomy 115 add_action( 'bp_init', array( $this, 'register_taxonomies' ) ); 116 117 // Eventually create/update the component terms mapping 118 add_action( 'bp_init', array( $this, 'component_terms' ), 999 ); 119 } 120 } 121 122 /** 123 * Set upload dirs and avatar globals 124 * 125 * @since BuddyPress (2.2.0) 126 */ 127 public function register_upload_datas() { 128 $bp = buddypress(); 129 130 $bp->{$this->id}->use_api = $this->use_api; 131 132 // Set upload dirs 133 $upload_data = bp_attachments_set_upload_dirs(); 134 135 if( ! empty( $upload_data ) && is_array( $upload_data ) ) { 136 foreach ( $upload_data as $key => $data ) { 137 // adding the uploads dir and url to Attachments component global. 138 $bp->{$this->id}->{$key} = $data; 139 } 140 } 141 142 if ( empty( $bp->avatar ) ) { 143 return; 144 } 145 146 if ( ! defined( 'BP_AVATAR_ORIGINAL_MAX_WIDTH' ) ) { 147 define( 'BP_AVATAR_ORIGINAL_MAX_WIDTH', 450 ); 148 } 149 150 if ( ! defined( 'BP_AVATAR_ORIGINAL_MAX_FILESIZE' ) ) { 151 152 if ( ! isset( $bp->site_options['fileupload_maxk'] ) ) { 153 define( 'BP_AVATAR_ORIGINAL_MAX_FILESIZE', 5120000 ); // 5mb 154 } else { 155 define( 'BP_AVATAR_ORIGINAL_MAX_FILESIZE', $bp->site_options['fileupload_maxk'] * 1024 ); 156 } 157 } 158 159 // Upload maximums 160 $bp->avatar->original_max_width = BP_AVATAR_ORIGINAL_MAX_WIDTH; 161 $bp->avatar->original_max_filesize = BP_AVATAR_ORIGINAL_MAX_FILESIZE; 162 163 // These have to be set on page load in order to avoid infinite filter loops at runtime 164 $bp->avatar->upload_path = bp_attachments_get_upload_dir(); 165 $bp->avatar->url = bp_attachments_get_upload_dir( 'url' ); 166 167 // Backpat for pre-1.5 168 if ( ! defined( 'BP_AVATAR_UPLOAD_PATH' ) ) { 169 define( 'BP_AVATAR_UPLOAD_PATH', $bp->avatar->upload_path ); 170 } 171 172 // Backpat for pre-1.5 173 if ( ! defined( 'BP_AVATAR_URL' ) ) { 174 define( 'BP_AVATAR_URL', $bp->avatar->url ); 175 } 176 } 177 178 /** 179 * Add the xProfile Change photo navigation 180 * 181 * @since BuddyPress (2.2.0) 182 * @param array $wp_admin_nav 183 */ 184 public function xprofile_setup_nav( $wp_admin_nav = array() ) { 185 $bp = buddypress(); 186 187 if ( empty( $bp->profile->slug ) || ! bp_attachments_avatar_is_enabled() ) { 188 return $wp_admin_nav; 189 } 190 191 // Determine user to use 192 if ( bp_displayed_user_domain() ) { 193 $user_domain = bp_displayed_user_domain(); 194 } elseif ( bp_loggedin_user_domain() ) { 195 $user_domain = bp_loggedin_user_domain(); 196 } else { 197 return $wp_admin_nav; 198 } 199 200 $profile_link = trailingslashit( $user_domain . $bp->profile->slug ); 201 202 if ( ! is_array( $wp_admin_nav ) ) { 203 bp_core_new_subnav_item( array( 204 'name' => _x( 'Change Profile Photo', 'Profile header sub menu', 'buddypress' ), 205 'slug' => 'change-avatar', 206 'parent_url' => $profile_link, 207 'parent_slug' => $bp->profile->slug, 208 'screen_function' => 'bp_attachments_screen_change_avatar', 209 'position' => 30, 210 'user_has_access' => bp_core_can_edit_settings() 211 ) ); 212 } else { 213 $profile_link = trailingslashit( bp_loggedin_user_domain() . $bp->profile->slug ); 214 215 $wp_admin_nav[] = array( 216 'parent' => 'my-account-' . $bp->profile->id, 217 'id' => 'my-account-' . $bp->profile->id . '-change-avatar', 218 'title' => _x( 'Change Profile Photo', 'My Account Profile sub nav', 'buddypress' ), 219 'href' => trailingslashit( $profile_link . 'change-avatar' ) 220 ); 221 222 return $wp_admin_nav; 223 } 224 } 225 226 /** 227 * Add the Group's avatar create step 228 * 229 * @since BuddyPress (2.2.0) 230 * @param array $group_creation_steps 231 */ 232 public function groups_setup_avatar_step( $group_creation_steps = array() ) { 233 $bp = buddypress(); 234 235 // If avatar uploads are not disabled, add avatar option 236 if ( bp_attachments_avatar_is_enabled() ) { 237 $group_creation_steps['group-avatar'] = array( 238 'name' => _x( 'Photo', 'Group screen nav', 'buddypress' ), 239 'position' => 20 240 ); 241 } 242 243 return $group_creation_steps; 244 } 245 246 /** 247 * Add the Group's change avatar nav 248 * 249 * @since BuddyPress (2.2.0) 250 * @param array $group_creation_steps 251 */ 252 public function groups_setup_manage_tab() { 253 if ( ! bp_is_group() || ! bp_attachments_avatar_is_enabled() ) { 254 return; 255 } 256 257 $group = groups_get_current_group(); 258 $admin_link = trailingslashit( bp_get_group_permalink( $group ) . 'admin' ); 259 260 bp_core_new_subnav_item( array( 261 'name' => __( 'Photo', 'buddypress' ), 262 'slug' => 'group-avatar', 263 'parent_url' => $admin_link, 264 'parent_slug' => $group->slug . '_manage', 265 'screen_function' => 'groups_screen_group_admin', 266 'position' => 20, 267 'user_has_access' => bp_is_item_admin(), 268 'show_in_admin_bar' => true, 269 ) ); 270 } 271 272 /** 273 * Register the Attachment post type 274 * 275 * @since BuddyPress (2.2.0) 276 */ 277 public function register_post_types() { 278 279 $bp_attachments_labels = array( 280 'name' => __( 'BuddyPress Attachments', 'buddypress' ), 281 'singular' => _x( 'Attachment', 'bp-attachments singular', 'buddypress' ), 282 'menu_name' => _x( 'Attachments', 'bp-attachments menu name', 'buddypress' ), 283 'all_items' => _x( 'All Attachments', 'bp-attachments all items', 'buddypress' ), 284 'singular_name' => _x( 'Attachment', 'bp-attachments singular name', 'buddypress' ), 285 'add_new' => _x( 'Add New Attachment', 'bp-attachments add new', 'buddypress' ), 286 'edit_item' => _x( 'Edit Attachment', 'bp-attachments edit item', 'buddypress' ), 287 'new_item' => _x( 'New Attachment', 'bp-attachments new item', 'buddypress' ), 288 'view_item' => _x( 'View Attachment', 'bp-attachments view item', 'buddypress' ), 289 'search_items' => _x( 'Search Attachments', 'bp-attachments search items', 'buddypress' ), 290 'not_found' => _x( 'No Attachments Found', 'bp-attachments not found', 'buddypress' ), 291 'not_found_in_trash' => _x( 'No Attachments Found in Trash', 'bp-attachments not found in trash', 'buddypress' ) 292 ); 293 294 $bp_attachments_args = array( 295 'label' => _x( 'Attachments', 'bp-attachments label', 'buddypress' ), 296 'labels' => $bp_attachments_labels, 297 'public' => false, 298 'rewrite' => false, 299 'show_ui' => false, // As BP Attachments can be activated on the network, we need to use a specific UI 300 'show_in_admin_bar' => false, 301 'show_in_nav_menus' => false, 302 'capabilities' => bp_attachments_get_attachment_caps(), 303 'capability_type' => array( 'bp_attachment', 'bp_attachments' ), 304 'delete_with_user' => true, 305 'supports' => array( 'title', 'author' ) 306 ); 307 308 // Register the post type for attachments. 309 register_post_type( 'bp_attachment', $bp_attachments_args ); 310 311 parent::register_post_types(); 312 } 313 314 /** 315 * Register the Component taxonomy 316 * 317 * @since BuddyPress (2.2.0) 318 */ 319 public function register_taxonomies() { 320 $labels = array( 321 'name' => _x( 'BuddyPress Components', 'bp-attachments taxonomy general name', 'buddypress' ), 322 'singular_name' => _x( 'Component', 'bp-attachments taxonomy singular name', 'buddypress' ), 323 'search_items' => _x( 'Search Components', 'bp-attachments search items', 'buddypress' ), 324 'all_items' => _x( 'All Components', 'bp-attachments all items', 'buddypress' ), 325 'parent_item' => _x( 'Parent Component', 'bp-attachments parent item', 'buddypress' ), 326 'parent_item_colon' => _x( 'Parent Component:', 'bp-attachments parent item colon', 'buddypress' ), 327 'edit_item' => _x( 'Edit Component', 'bp-attachments edit item', 'buddypress' ), 328 'update_item' => _x( 'Update Component', 'bp-attachments update item', 'buddypress' ), 329 'add_new_item' => _x( 'Add New Component', 'bp-attachments add new item', 'buddypress' ), 330 'new_item_name' => _x( 'New Component Name', 'bp-attachments new item name', 'buddypress' ), 331 'menu_name' => _x( 'BP Component', 'bp-attachments menu name', 'buddypress' ), 332 ); 333 334 $args = array( 335 'hierarchical' => true, 336 'labels' => $labels, 337 'show_ui' => true, 338 'show_admin_column' => true, 339 'query_var' => false, 340 'rewrite' => false, 341 'capabilities' => bp_attachments_get_component_caps(), 342 'update_count_callback' => '_update_generic_term_count', 343 ); 344 345 // Register the taxonomy for attachments. 346 register_taxonomy( 'bp_component', array( 'bp_attachment' ), $args ); 347 348 parent::register_taxonomies(); 349 } 350 351 /** 352 * Map component ids with term ids if needed 353 * 354 * @since BuddyPress (2.2.0) 355 */ 356 public function component_terms() { 357 $bp = buddypress(); 358 359 // Get terms mapping 360 $terms_mapping = bp_get_option( 'bp_attachments_term_ids', array() ); 361 $terms_toadd = array(); 362 363 // Loop in loaded components to check if the ones who need attachments are already mapped 364 foreach ( array_keys( $bp->loaded_components ) as $component_id ) { 365 if ( ! empty( $bp->{$component_id}->can_attachments ) && empty( $terms_mapping[ $bp->{$component_id}->id ] ) ) { 366 $terms_toadd[ $bp->{$component_id}->id ] = array( 367 'name' => $bp->{$component_id}->name, 368 'slug' => $bp->{$component_id}->slug 369 ); 370 } 371 } 372 373 // No term to add, simply globalize the terms 374 if ( empty( $terms_toadd ) ) { 375 $bp->{$this->id}->component_terms = $terms_mapping; 376 return; 377 } 378 379 // Insert needed terms and build the mapping 380 foreach ( $terms_toadd as $key => $component ) { 381 $component_term = wp_insert_term( $component['name'], 'bp_component', array( 'slug' => $component['slug'] ) ); 382 383 if ( ! empty( $component_term['term_id'] ) ) { 384 $terms_mapping[ $key ] = $component_term['term_id']; 385 } 386 } 387 388 // Update terms mapping and globalize it 389 bp_update_option( 'bp_attachments_term_ids', $terms_mapping ); 390 $bp->{$this->id}->component_terms = $terms_mapping; 391 } 392 } 393 394 /** 395 * Bootstrap the Attachments component. 396 */ 397 function bp_setup_attachments() { 398 buddypress()->attachments = new BP_Attachments_Component(); 399 } 400 add_action( 'bp_setup_components', 'bp_setup_attachments', 6 ); -
src/bp-attachments/bp-attachments-screens.php
diff --git src/bp-attachments/bp-attachments-screens.php src/bp-attachments/bp-attachments-screens.php index e69de29..3e98e8a 100644
1 <?php 2 /** 3 * Attachments Screens. 4 * 5 * @package BuddyPress 6 * @subpackage Attachments Screens 7 */ 8 9 // Exit if accessed directly 10 defined( 'ABSPATH' ) or exit; 11 12 /** 13 * Handles the uploading and cropping of a user avatar. Displays the change avatar page. 14 * 15 * @since BuddyPress (2.2.0) 16 * 17 * @package BuddyPress 18 * @subpackage Attachments Screens 19 * 20 * @uses bp_is_my_profile() Checks to make sure the current user being viewed equals the logged in user 21 * @uses bp_core_load_template() Looks for and loads a template file within the current member theme (folder/filename) 22 */ 23 function bp_attachments_screen_change_avatar() { 24 // Bail if not the correct screen 25 if ( ! bp_is_my_profile() && ! bp_current_user_can( 'bp_moderate' ) ) { 26 return false; 27 } 28 29 // Bail if there are action variables 30 if ( bp_action_variables() ) { 31 bp_do_404(); 32 return; 33 } 34 35 $bp = buddypress(); 36 37 if ( ! isset( $bp->avatar_admin ) ) { 38 $bp->avatar_admin = new stdClass(); 39 } 40 41 $bp->avatar_admin->step = 'upload-image'; 42 $user_id = bp_displayed_user_id(); 43 44 if ( ! empty( $_FILES ) ) { 45 46 // Check the nonce 47 check_admin_referer( 'bp_avatar_upload' ); 48 49 // Pass the file to the avatar upload handler 50 $uploaded_avatar = bp_attachments_avatar_handle_upload( $_FILES, 'xprofile', $user_id ); 51 52 if ( is_wp_error( $uploaded_avatar ) ) { 53 bp_core_add_message( $uploaded_avatar->get_error_message(), 'error' ); 54 55 // Go to crop step 56 } else { 57 // Avoid some error messages to be output if 58 // everything is ok. 59 $bp->template_message = false; 60 $bp->avatar_admin->step = 'crop-image'; 61 62 // Make sure we include the jQuery jCrop file for image cropping 63 add_action( 'wp_print_scripts', 'bp_attachments_add_jquery_cropper' ); 64 } 65 } 66 67 // If the image cropping is done, crop the image and save a full/thumb version 68 if ( isset( $_POST['avatar-crop-submit'] ) ) { 69 70 // Check the nonce 71 check_admin_referer( 'bp_avatar_cropstore' ); 72 73 $args = array( 74 'item_id' => $user_id, 75 'original_file' => $_POST['image_src'], 76 'crop_x' => $_POST['x'], 77 'crop_y' => $_POST['y'], 78 'crop_w' => $_POST['w'], 79 'crop_h' => $_POST['h'] 80 ); 81 82 if ( ! bp_attachments_avatar_handle_crop( $args ) ) { 83 bp_core_add_message( __( 'There was a problem cropping your profile photo.', 'buddypress' ), 'error' ); 84 } else { 85 do_action( 'xprofile_avatar_uploaded' ); 86 bp_core_add_message( __( 'Your new profile photo was uploaded successfully.', 'buddypress' ) ); 87 bp_core_redirect( bp_displayed_user_domain() ); 88 } 89 } 90 91 do_action( 'xprofile_screen_change_avatar' ); 92 93 bp_core_load_template( apply_filters( 'xprofile_template_change_avatar', 'members/single/home' ) ); 94 } 95 96 /** 97 * Handle the display of a group's Change Avatar page. 98 * 99 * @since BuddyPress (2.2.0) 100 */ 101 function bp_attachments_screen_group_admin_avatar() { 102 103 if ( 'group-avatar' != bp_get_group_current_admin_tab() ) { 104 return false; 105 } 106 107 // If the logged-in user doesn't have permission or if avatar uploads are disabled, then stop here 108 if ( ! bp_is_item_admin() || ! bp_attachments_avatar_is_enabled() ) { 109 return false; 110 } 111 112 $bp = buddypress(); 113 114 // If the group admin has deleted the admin avatar 115 if ( bp_is_action_variable( 'delete', 1 ) ) { 116 117 // Check the nonce 118 check_admin_referer( 'bp_group_avatar_delete' ); 119 120 if ( bp_attachments_delete_existing_avatar( array( 'item_id' => $bp->groups->current_group->id, 'object' => 'group' ) ) ) { 121 bp_core_add_message( __( 'The group profile photo was deleted successfully!', 'buddypress' ) ); 122 } else { 123 bp_core_add_message( __( 'There was a problem deleting the group profile photo; please try again.', 'buddypress' ), 'error' ); 124 } 125 } 126 127 if ( ! isset( $bp->avatar_admin ) ) { 128 $bp->avatar_admin = new stdClass(); 129 } 130 131 $bp->avatar_admin->step = 'upload-image'; 132 133 if ( !empty( $_FILES ) ) { 134 135 // Check the nonce 136 check_admin_referer( 'bp_avatar_upload' ); 137 138 // Pass the file to the avatar upload handler 139 $uploaded_avatar = bp_attachments_avatar_handle_upload( $_FILES, 'groups', $bp->groups->current_group->id ); 140 141 if ( is_wp_error( $uploaded_avatar ) ) { 142 bp_core_add_message( $uploaded_avatar->get_error_message(), 'error' ); 143 144 // Go to crop step 145 } else { 146 // Avoid some error messages to be output if 147 // everything is ok. 148 $bp->template_message = false; 149 $bp->avatar_admin->step = 'crop-image'; 150 151 // Make sure we include the jQuery jCrop file for image cropping 152 add_action( 'wp_print_scripts', 'bp_attachments_add_jquery_cropper' ); 153 } 154 } 155 156 // If the image cropping is done, crop the image and save a full/thumb version 157 if ( isset( $_POST['avatar-crop-submit'] ) ) { 158 159 // Check the nonce 160 check_admin_referer( 'bp_avatar_cropstore' ); 161 162 $args = array( 163 'object' => 'group', 164 'avatar_dir' => 'avatar_group_dir', 165 'item_id' => $bp->groups->current_group->id, 166 'original_file' => $_POST['image_src'], 167 'crop_x' => $_POST['x'], 168 'crop_y' => $_POST['y'], 169 'crop_w' => $_POST['w'], 170 'crop_h' => $_POST['h'] 171 ); 172 173 if ( ! bp_attachments_avatar_handle_crop( $args ) ) { 174 bp_core_add_message( __( 'There was a problem cropping the group profile photo.', 'buddypress' ), 'error' ); 175 } else { 176 bp_core_add_message( __( 'The new group profile photo was uploaded successfully.', 'buddypress' ) ); 177 } 178 } 179 180 do_action( 'groups_screen_group_admin_avatar', $bp->groups->current_group->id ); 181 182 bp_core_load_template( apply_filters( 'groups_template_group_admin_avatar', 'groups/single/home' ) ); 183 } 184 add_action( 'bp_screens', 'bp_attachments_screen_group_admin_avatar' ); 185 186 /** 187 * Move the avatar in user's folder once the signup activated 188 * 189 * @since BuddyPress (2.2.0) 190 */ 191 function bp_attachments_avatar_activate_signup_screen( $hashed_key = '', $user = 0 ) { 192 if ( empty( $hashed_key ) || empty( $user ) ) { 193 return; 194 } 195 196 // Check if the avatar folder exists. If it does, move rename it, move 197 // it and delete the signup avatar dir 198 if ( file_exists( bp_attachments_get_upload_dir( 'avatar_user_dir' ) . '/signups/' . $hashed_key ) ) { 199 @rename( bp_attachments_get_upload_dir( 'avatar_user_dir' ) . '/signups/' . $hashed_key, bp_attachments_get_upload_dir( 'avatar_user_dir' ) . '/' . $user ); 200 } 201 } 202 add_action( 'bp_core_activate_account_avatar', 'bp_attachments_avatar_activate_signup_screen', 10, 2 ); -
src/bp-attachments/js/script.js
diff --git src/bp-attachments/js/script.js src/bp-attachments/js/script.js index e69de29..35b9b5d 100644
1 var bp = bp || {}; 2 3 /** 4 * BP Attachments Editor ! 5 */ 6 ( function( $ ) { 7 var BPmedia; 8 9 bp.media = BPmedia = {}; 10 11 // map bp.media to wp.media 12 bp.media = wp.media; 13 14 bp.media.params = { 15 item_id: _wpPluploadSettings.defaults.multipart_params.item_id, 16 item_component: _wpPluploadSettings.defaults.multipart_params.component, 17 item_type: _wpPluploadSettings.defaults.multipart_params.item_type, 18 item_post_id: _wpPluploadSettings.defaults.multipart_params.post_id, 19 nonce: _wpPluploadSettings.defaults.multipart_params._bpnonce, 20 callback: _wpPluploadSettings.defaults.multipart_params.callback, 21 callback_id: _wpPluploadSettings.defaults.multipart_params.callback_id, 22 }; 23 24 _.extend( BPmedia, { model: {}, view: {}, controller: {}, frames: {} } ); 25 26 // Models 27 bp.media.attachment = function( id ) { 28 return BPattachment.get( id ); 29 }; 30 31 /** 32 * bp.media.model.Attachment 33 * 34 * It's an adpated copy of WordPress Attachment model 35 * 36 * @constructor 37 * @augments Backbone.Model 38 */ 39 BPattachment = BPmedia.model.Attachment = bp.media.model.Attachment.extend({ 40 41 /** 42 * Triggered when attachment details change 43 * Overrides Backbone.Model.sync 44 * 45 * @param {string} method 46 * @param {bp.media.model.Attachment} model 47 * @param {Object} [options={}] 48 * 49 * @returns {Promise} 50 */ 51 sync: function( method, model, options ) { 52 // If the attachment does not yet have an `id`, return an instantly 53 // rejected promise. Otherwise, all of our requests will fail. 54 if ( _.isUndefined( this.id ) ) { 55 return $.Deferred().rejectWith( this ).promise(); 56 } 57 58 // Overload the `read` request so Attachment.fetch() functions correctly. 59 if ( 'read' === method ) { 60 options = options || {}; 61 options.context = this; 62 options.data = _.extend( options.data || {}, { 63 action: 'get_bp_attachment', 64 id: this.id 65 }); 66 return bp.media.ajax( options ); 67 68 // Overload the `update` request so properties can be saved. 69 } else if ( 'update' === method ) { 70 // If we do not have the necessary nonce, fail immeditately. 71 if ( ! this.get('nonces') || ! this.get('nonces').update ) { 72 return $.Deferred().rejectWith( this ).promise(); 73 } 74 75 options = options || {}; 76 options.context = this; 77 78 // Set the action and ID. 79 options.data = _.extend( options.data || {}, { 80 action: 'update_bp_attachment', 81 id: this.id, 82 nonce: this.get('nonces').update, 83 post_id: bp.media.model.settings.post.id 84 }); 85 86 // Record the values of the changed attributes. 87 if ( model.hasChanged() ) { 88 options.data.changes = {}; 89 90 _.each( model.changed, function( value, key ) { 91 options.data.changes[ key ] = this.get( key ); 92 }, this ); 93 } 94 95 return bp.media.ajax( options ); 96 97 // Overload the `delete` request so attachments can be removed. 98 // This will permanently delete an attachment. 99 } else if ( 'delete' === method ) { 100 options = options || {}; 101 102 if ( ! options.wait ) { 103 this.destroyed = true; 104 } 105 106 options.context = this; 107 options.data = _.extend( options.data || {}, { 108 action: 'delete_bp_attachment', 109 id: this.id, 110 _wpnonce: this.get('nonces')['delete'] 111 }); 112 113 return bp.media.ajax( options ).done( function() { 114 this.destroyed = true; 115 }).fail( function() { 116 this.destroyed = false; 117 }); 118 119 // Otherwise, fall back to `Backbone.sync()`. 120 } else { 121 /** 122 * Call `sync` directly on Backbone.Model 123 */ 124 return bp.media.model.Attachment.prototype.sync.apply( this, arguments ); 125 } 126 }, 127 /** 128 * Convert date strings into Date objects. 129 * 130 * @param {Object} resp The raw response object, typically returned by fetch() 131 * @returns {Object} The modified response object, which is the attributes hash 132 * to be set on the model. 133 */ 134 parse: function( resp ) { 135 if ( ! resp ) { 136 return resp; 137 } 138 139 resp.date = new Date( resp.date ); 140 resp.modified = new Date( resp.modified ); 141 return resp; 142 }, 143 }, { 144 /** 145 * Add a model to the end of the static 'all' collection and return it. 146 * 147 * @static 148 * @param {Object} attrs 149 * @returns {wp.media.model.Attachment} 150 */ 151 create: function( attrs ) { 152 return BPattachments.all.push( attrs ); 153 }, 154 /** 155 * Retrieve a model, or add it to the end of the static 'all' collection before returning it. 156 * 157 * @static 158 * @param {string} id A string used to identify a model. 159 * @param {Backbone.Model|undefined} attachment 160 * @returns {wp.media.model.Attachment} 161 */ 162 get: _.memoize( function( id, attachment ) { 163 return BPattachments.all.push( attachment || { id: id } ); 164 }) 165 }); 166 167 /** 168 * Override media.model.Attachment.create function 169 * so that the uploader is using BPattachment model 170 */ 171 bp.media.model.Attachment.create = function( attrs ) { 172 return BPattachments.all.push( attrs ); 173 }; 174 175 /** 176 * Override media.model.Attachment.get function 177 * so that the uploader is using BPattachment model 178 */ 179 bp.media.model.Attachment.get = _.memoize( function( id, attachment ) { 180 return BPattachments.all.push( attachment || { id: id } ); 181 } ); 182 183 /** 184 * bp.media.model.BPattachments 185 * 186 * it's an adapted copy of WordPress Attachments Collection 187 * 188 * @constructor 189 * @augments Backbone.Collection 190 */ 191 BPattachments = bp.media.model.Attachments.extend({ 192 /** 193 * @type {wp.media.model.Attachment} 194 */ 195 model: BPattachment, 196 /** 197 * @param {Array} [models=[]] Array of models used to populate the collection. 198 * @param {Object} [options={}] 199 */ 200 initialize: function( models, options ) { 201 options = options || {}; 202 203 bp.media.model.Attachments.prototype.initialize.apply( this, arguments ); 204 }, 205 206 /** 207 * @access private 208 */ 209 _requery: function() { 210 if ( this.props.get('query') ) { 211 this.mirror( bp.media.model.Query.get( this.props.toJSON() ) ); 212 } 213 }, 214 215 parse: function( resp, xhr ) { 216 if ( ! _.isArray( resp ) ) { 217 resp = [resp]; 218 } 219 220 return _.map( resp, function( attrs ) { 221 var id, attachment, newAttributes; 222 223 if ( attrs instanceof Backbone.Model ) { 224 id = attrs.get( 'id' ); 225 attrs = attrs.attributes; 226 } else { 227 id = attrs.id; 228 } 229 230 attachment = BPattachment.get( id ); 231 newAttributes = attachment.parse( attrs, xhr ); 232 233 if ( ! _.isEqual( attachment.attributes, newAttributes ) ) { 234 attachment.set( newAttributes ); 235 } 236 237 return attachment; 238 }); 239 }, 240 241 }); 242 243 /** 244 * @static 245 * @member {bp.media.model.BPattachments} 246 */ 247 BPattachments.all = new BPattachments(); 248 249 /** 250 * bp.media.model.Avatar 251 * 252 * @constructor 253 * @augments Backbone.Model 254 */ 255 Avatar = bp.media.model.Avatar = Backbone.Model.extend( { 256 defaults : { 257 id: 0, 258 title: '', 259 component: '', 260 filename: '', 261 url:'', 262 path:'', 263 }, 264 } ); 265 266 /** 267 * bp.media.model.Query 268 * 269 * It's an adpated copy of WordPress Query 270 * 271 * @constructor 272 * @augments Backbone.Model 273 */ 274 BPquery = BPmedia.model.Query = bp.media.model.Query = BPattachments.extend({ 275 276 initialize: function( models, options ) { 277 var allowed; 278 279 options = options || {}; 280 BPattachments.prototype.initialize.apply( this, arguments ); 281 282 this.args = options.args; 283 this._hasMore = true; 284 this.created = new Date(); 285 286 this.filters.order = function( attachment ) { 287 var orderby = this.props.get('orderby'), 288 order = this.props.get('order'); 289 290 if ( ! this.comparator ) { 291 return true; 292 } 293 294 // We want any items that can be placed before the last 295 // item in the set. If we add any items after the last 296 // item, then we can't guarantee the set is complete. 297 if ( this.length ) { 298 return 1 !== this.comparator( attachment, this.last(), { ties: true }); 299 300 // Handle the case where there are no items yet and 301 // we're sorting for recent items. In that case, we want 302 // changes that occurred after we created the query. 303 } else if ( 'DESC' === order && ( 'date' === orderby || 'modified' === orderby ) ) { 304 return attachment.get( orderby ) >= this.created; 305 306 // If we're sorting by menu order and we have no items, 307 // accept any items that have the default menu order (0). 308 } else if ( 'ASC' === order && 'menuOrder' === orderby ) { 309 return attachment.get( orderby ) === 0; 310 } 311 312 // Otherwise, we don't want any items yet. 313 return false; 314 }; 315 316 // Observe the central `wp.Uploader.queue` collection to watch for 317 // new matches for the query. 318 // 319 // Only observe when a limited number of query args are set. There 320 // are no filters for other properties, so observing will result in 321 // false positives in those queries. 322 allowed = [ 's', 'order', 'orderby', 'posts_per_page', 'post_mime_type', 'post_parent', 'component', 'item_type', 'item_id' ]; 323 if ( wp.Uploader && _( this.args ).chain().keys().difference( allowed ).isEmpty().value() ) { 324 this.observe( wp.Uploader.queue ); 325 } 326 }, 327 /** 328 * @returns {Boolean} 329 */ 330 hasMore: function() { 331 return this._hasMore; 332 }, 333 /** 334 * @param {Object} [options={}] 335 * @returns {Promise} 336 */ 337 more: function( options ) { 338 var query = this; 339 340 if ( this._more && 'pending' === this._more.state() ) { 341 return this._more; 342 } 343 344 if ( ! this.hasMore() || 'avatar' == this.args.item_type ) { 345 return $.Deferred().resolveWith( this ).promise(); 346 } 347 348 options = options || {}; 349 options.remove = false; 350 351 return this._more = this.fetch( options ).done( function( resp ) { 352 if ( _.isEmpty( resp ) || -1 === this.args.posts_per_page || resp.length < this.args.posts_per_page ) { 353 query._hasMore = false; 354 } 355 }); 356 }, 357 358 sync: function( method, model, options ) { 359 var args, fallback; 360 361 // Overload the read method so BPattachment.fetch() functions correctly. 362 if ( 'read' === method ) { 363 options = options || {}; 364 options.context = this; 365 366 if ( 'avatar' == this.args.item_type ) { 367 return false; 368 } 369 370 options.data = _.extend( options.data || {}, { 371 action: 'query_bp_attachments', 372 post_id: bp.media.model.settings.post.id 373 }); 374 375 // Clone the args so manipulation is non-destructive. 376 args = _.clone( this.args ); 377 378 // Determine which page to query. 379 if ( -1 !== args.posts_per_page ) { 380 args.paged = Math.floor( this.length / args.posts_per_page ) + 1; 381 } 382 383 options.data.query = args; 384 return bp.media.ajax( options ); 385 386 // Otherwise, fall back to Backbone.sync() 387 } else { 388 /** 389 * Call bp.media.model.BPattachments.sync or Backbone.sync 390 */ 391 fallback = BPattachments.prototype.sync ? BPattachments.prototype : Backbone; 392 return fallback.sync.apply( this, arguments ); 393 } 394 } 395 396 }, { 397 /** 398 * @readonly 399 */ 400 defaultProps: { 401 orderby: 'date', 402 order: 'DESC', 403 component: bp.media.params.item_component, 404 item_type: bp.media.params.item_type, 405 item_id: bp.media.params.item_id, 406 }, 407 /** 408 * @readonly 409 */ 410 defaultArgs: { 411 posts_per_page: 40 412 }, 413 /** 414 * @readonly 415 */ 416 orderby: { 417 allowed: [ 'name', 'author', 'date', 'title', 'modified', 'uploadedTo', 'id', 'post__in', 'menuOrder' ], 418 valuemap: { 419 'id': 'ID', 420 'uploadedTo': 'parent', 421 'attachedTo': 'item_id', 422 'menuOrder': 'menu_order ID' 423 } 424 }, 425 /** 426 * @readonly 427 */ 428 propmap: { 429 'search': 's', 430 'type': 'post_mime_type', 431 'perPage': 'posts_per_page', 432 'menuOrder': 'menu_order', 433 'uploadedTo': 'post_parent', 434 'attachedTo': 'item_id', 435 }, 436 /** 437 * @static 438 * @method 439 * 440 * @returns {wp.media.model.Query} A new query. 441 */ 442 // Caches query objects so queries can be easily reused. 443 get: (function(){ 444 /** 445 * @static 446 * @type Array 447 */ 448 var queries = []; 449 450 /** 451 * @param {Object} props 452 * @param {Object} options 453 * @returns {Query} 454 */ 455 return function( props, options ) { 456 var args = {}, 457 orderby = BPquery.orderby, 458 defaults = BPquery.defaultProps, 459 query; 460 461 // Remove the `query` property. This isn't linked to a query, 462 // this *is* the query. 463 delete props.query; 464 465 // Fill default args. 466 _.defaults( props, defaults ); 467 468 // Normalize the order. 469 props.order = props.order.toUpperCase(); 470 if ( 'DESC' !== props.order && 'ASC' !== props.order ) { 471 props.order = defaults.order.toUpperCase(); 472 } 473 474 // Ensure we have a valid orderby value. 475 if ( ! _.contains( orderby.allowed, props.orderby ) ) { 476 props.orderby = defaults.orderby; 477 } 478 479 // Generate the query `args` object. 480 // Correct any differing property names. 481 _.each( props, function( value, prop ) { 482 if ( _.isNull( value ) ) { 483 return; 484 } 485 486 args[ BPquery.propmap[ prop ] || prop ] = value; 487 }); 488 489 // Fill any other default query args. 490 _.defaults( args, BPquery.defaultArgs ); 491 492 // `props.orderby` does not always map directly to `args.orderby`. 493 // Substitute exceptions specified in orderby.keymap. 494 args.orderby = orderby.valuemap[ props.orderby ] || props.orderby; 495 496 // Search the query cache for matches. 497 query = _.find( queries, function( query ) { 498 return _.isEqual( query.args, args ); 499 }); 500 501 // Otherwise, create a new query and add it to the cache. 502 if ( ! query ) { 503 query = new BPquery( [], _.extend( options || {}, { 504 props: props, 505 args: args 506 } ) ); 507 queries.push( query ); 508 } 509 510 return query; 511 }; 512 }()) 513 514 }); 515 516 bp.media.query = function( props ) { 517 return new BPattachments( null, { 518 props: _.extend( _.defaults( props || {}, { orderby: 'date' } ), { query: true } ) 519 }); 520 }; 521 522 bp.media.controller.bpLibrary = bp.media.controller.Library.extend({ 523 defaults: { 524 id: 'bp_library', 525 multiple: false, 526 describe: false, 527 toolbar: 'bp_select', 528 sidebar: 'bp_settings', 529 content: 'bp_upload', 530 router: 'bp_browse', 531 menu: 'default', 532 searchable: false, 533 filterable: false, 534 sortable: false, 535 title: bp.media.view.l10n.bp_attachments.title, 536 537 // Uses a user setting to override the content mode. 538 contentUserSetting: false, 539 540 // Sync the selection from the last state when 'multiple' matches. 541 syncSelection: true 542 }, 543 544 initialize: function() { 545 type = ''; 546 547 if ( 'avatar' == bp.media.params.item_type ) { 548 type = { type: 'image' }; 549 } 550 551 if ( ! this.get('library') ) { 552 this.set( 'library', bp.media.query( type ) ); 553 } 554 555 bp.media.controller.Library.prototype.initialize.apply( this, arguments ); 556 }, 557 558 uploading: function( attachment ) { 559 var content = this.frame.content, 560 mode = 'bpbrowse'; 561 562 if ( 'avatar' == bp.media.params.item_type ) 563 mode = 'crop'; 564 565 if ( 'bp_upload' === content.mode() ) { 566 this.frame.content.mode( mode ); 567 } 568 569 this.get('selection').add( attachment ); 570 }, 571 572 }); 573 574 BPmedia.view.Avatar = bp.media.view.Avatar = bp.media.view.Attachment.extend( { 575 tagName: 'li', 576 className: 'avatar', 577 template: bp.media.template('avatar'), 578 579 initialize: function() { 580 var selection = this.options.selection; 581 582 bp.media.view.Attachment.prototype.initialize.apply( this, arguments ); 583 }, 584 585 render: function() { 586 var selection = this.options.selection; 587 588 bp.media.view.Attachment.prototype.render.apply( this, arguments ); 589 590 if( ! _.isUndefined( selection.single() ) && ! selection.single()._changing ) { 591 var tocrop = this.$el.find( 'img' ); 592 var ratio = 1; 593 594 if ( ! _.isUndefined( bp.media.view.settings.bp_attachments.full_h ) && ! _.isUndefined( bp.media.view.settings.bp_attachments.full_w ) && bp.media.view.settings.bp_attachments.full_h != bp.media.view.settings.bp_attachments.full_w ) { 595 ratio = bp.media.view.settings.bp_attachments.full_h / bp.media.view.settings.bp_attachments.full_w; 596 } 597 598 crop_left = Math.round( selection.single().get('width' ) / 4 ); 599 crop_top = Math.round( selection.single().get('height' ) / 4 ); 600 crop_right = selection.single().get('width' ) - crop_left; 601 crop_bottom = selection.single().get('height' ) - crop_top; 602 603 tocrop.Jcrop({ 604 onChange: this.showPreview, 605 onSelect: this.showPreview, 606 onSelect: this.updateCoords, 607 aspectRatio: ratio, 608 setSelect: [ crop_left, crop_top, crop_right, crop_bottom ] 609 }); 610 611 this.updateCoords({x: crop_left, y: crop_top, w: crop_right, h: crop_bottom}); 612 613 } 614 615 return this; 616 }, 617 618 updateCoords: function( args ) { 619 var selection = BPmedia.frame().state().get( 'selection' ).single(); 620 621 // Need to find a better way 622 selection.attributes.x = args.x; 623 selection.attributes.y = args.y; 624 selection.attributes.w = args.w; 625 selection.attributes.h = args.h; 626 }, 627 628 showPreview: function( coords ) { 629 var selection = BPmedia.frame().state().get( 'selection' ).single(); 630 631 // For some reason, the Avatar Detail view is not rendered 632 $( '#avatar-crop-preview' ).prop( 'src', selection.get( 'url') ); 633 634 if ( parseInt(coords.w) > 0 ) { 635 var fw = bp.media.view.settings.bp_attachments.full_w; 636 var fh = bp.media.view.settings.bp_attachments.full_h; 637 var rx = fw / coords.w; 638 var ry = fh / coords.h; 639 640 $( '#avatar-crop-preview' ).css( { 641 maxWidth:'none', 642 width: Math.round(rx * selection.get('width') )+ 'px', 643 height: Math.round(ry * selection.get('height') )+ 'px', 644 marginLeft: '-' + Math.round(rx * coords.x) + 'px', 645 marginTop: '-' + Math.round(ry * coords.y) + 'px' 646 } ); 647 } 648 }, 649 } ); 650 651 bp.media.view.AvatarDetails = bp.media.view.Attachment.Details.extend({ 652 653 tagName: 'div', 654 className: 'attachment-details', 655 template: bp.media.template('bp-avatar-details'), 656 657 render: function() { 658 var options = _.defaults( this.model.toJSON(), { 659 orientation: 'landscape', 660 uploading: false, 661 type: '', 662 subtype: '', 663 icon: '', 664 filename: '', 665 caption: '', 666 title: '', 667 dateFormatted: '', 668 width: '', 669 height: '', 670 compat: false, 671 alt: '', 672 description: '' 673 }); 674 675 options.buttons = this.buttons; 676 options.describe = this.controller.state().get('describe'); 677 678 if ( 'image' === options.type ) { 679 options.size = this.imageSize(); 680 } 681 682 options.can = {}; 683 if ( options.nonces ) { 684 options.can.remove = !! options.nonces['delete']; 685 options.can.save = !! options.nonces.update; 686 } 687 688 if ( this.controller.state().get('allowLocalEdits') ) { 689 options.allowLocalEdits = true; 690 } 691 692 this.views.detach(); 693 this.$el.html( this.template( options ) ); 694 695 this.$el.toggleClass( 'uploading', options.uploading ); 696 if ( options.uploading ) { 697 this.$bar = this.$('.media-progress-bar div'); 698 } else { 699 delete this.$bar; 700 } 701 702 // Check if the model is selected. 703 this.updateSelect(); 704 705 // Update the save status. 706 this.updateSave(); 707 708 /** 709 * 710 * ! this is not rendered ? 711 * 712 * 713 */ 714 this.views.render(); 715 716 return this; 717 }, 718 }); 719 720 bp.media.view.AttachmentsDetails = bp.media.view.Attachment.Details.extend({ 721 722 tagName: 'div', 723 className: 'attachment-details', 724 template: bp.media.template('bp-attachment-details'), 725 726 render: function() { 727 var options = _.defaults( this.model.toJSON(), { 728 orientation: 'landscape', 729 uploading: false, 730 type: '', 731 subtype: '', 732 icon: '', 733 filename: '', 734 caption: '', 735 title: '', 736 dateFormatted: '', 737 width: '', 738 height: '', 739 compat: false, 740 alt: '', 741 description: '' 742 }); 743 744 options.buttons = this.buttons; 745 options.describe = this.controller.state().get('describe'); 746 747 if ( 'image' === options.type ) { 748 options.size = this.imageSize(); 749 } 750 751 options.can = {}; 752 if ( options.nonces ) { 753 options.can.remove = !! options.nonces['delete']; 754 options.can.save = !! options.nonces.update; 755 } 756 757 if ( this.controller.state().get('allowLocalEdits') ) { 758 options.allowLocalEdits = true; 759 } 760 761 this.views.detach(); 762 this.$el.html( this.template( options ) ); 763 764 this.$el.toggleClass( 'uploading', options.uploading ); 765 if ( options.uploading ) { 766 this.$bar = this.$('.media-progress-bar div'); 767 } else { 768 delete this.$bar; 769 } 770 771 // Check if the model is selected. 772 this.updateSelect(); 773 774 // Update the save status. 775 this.updateSave(); 776 777 this.views.render(); 778 779 return this; 780 }, 781 782 }); 783 784 BPmedia.view.AttachmentsBrowser = bp.media.view.BPattachmentsBrowser = bp.media.view.AttachmentsBrowser.extend({ 785 786 createToolbar: function () { 787 bp.media.view.AttachmentsBrowser.prototype.createToolbar.apply( this, arguments ); 788 789 // Remove the date field and label 790 this.toolbar.unset( 'dateFilterLabel' ); 791 this.toolbar.unset( 'dateFilter' ); 792 }, 793 794 createSingle: function() { 795 var sidebar = this.sidebar, 796 single = this.options.selection.single(); 797 798 sidebar.set( 'details', new bp.media.view.AttachmentsDetails({ 799 controller: this.controller, 800 model: single, 801 priority: 80 802 }) ); 803 804 if ( this.options.display ) { 805 sidebar.set( 'display', new bp.media.view.Settings.AttachmentDisplay({ 806 controller: this.controller, 807 model: this.model.display( single ), 808 attachment: single, 809 priority: 160, 810 userSettings: this.model.get('displayUserSettings') 811 }) ); 812 } 813 }, 814 }); 815 816 BPmedia.view.AvatarCroper = bp.media.view.AvatarCroper = bp.media.view.AttachmentsBrowser.extend( { 817 tagName: 'div', 818 className: 'attachments-browser', 819 820 initialize: function() { 821 _.defaults( this.options, { 822 filters: false, 823 search: false, 824 display: false, 825 826 AttachmentView: bp.media.view.Avatar 827 }); 828 829 this.createToolbar(); 830 this.updateContent(); 831 this.createSidebar(); 832 833 this.collection.on( 'add remove reset', this.updateContent, this ); 834 this.on( 'ready', this.customizeUploader, this ); 835 }, 836 837 customizeUploader:function(){ 838 $( '.upload-ui h3.upload-instructions' ).html( 'Drop your avatar anywhere to upload' ); 839 $( '.upload-ui a.button-hero' ).html( 'Select an image' ); 840 }, 841 842 createToolbar: function () { 843 bp.media.view.AttachmentsBrowser.prototype.createToolbar.apply( this, arguments ); 844 845 // Remove the date field and label 846 this.toolbar.unset( 'dateFilterLabel' ); 847 this.toolbar.unset( 'dateFilter' ); 848 }, 849 850 updateContent: function() { 851 var view = this; 852 853 if( ! this.attachments ) { 854 this.createAttachments(); 855 } 856 857 if ( ! this.collection.length ) { 858 this.collection.more().done( function() { 859 if ( ! view.collection.length ) { 860 view.createUploader(); 861 } 862 }); 863 } 864 }, 865 866 createAttachments: function() { 867 this.removeContent(); 868 869 this.attachments = new bp.media.view.Attachments({ 870 controller: this.controller, 871 collection: this.collection, 872 selection: this.options.selection, 873 model: this.model, 874 sortable: this.options.sortable, 875 876 // The single `Attachment` view to be used in the `Attachments` view. 877 AttachmentView: this.options.AttachmentView 878 }); 879 880 this.views.add( this.attachments ); 881 }, 882 883 removeContent: function() { 884 _.each(['attachments','uploader'], function( key ) { 885 if ( this[ key ] ) { 886 this[ key ].remove(); 887 delete this[ key ]; 888 } 889 }, this ); 890 }, 891 892 createSidebar: function() { 893 var options = this.options, 894 selection = options.selection, 895 sidebar = this.sidebar = new bp.media.view.Sidebar({ 896 controller: this.controller 897 }); 898 899 this.views.add( sidebar ); 900 901 if ( this.controller.uploader ) { 902 sidebar.set( 'uploads', new bp.media.view.UploaderStatus({ 903 controller: this.controller, 904 priority: 40 905 }) ); 906 } 907 908 selection.on( 'selection:single', this.createSingle, this ); 909 selection.on( 'selection:unsingle', this.disposeSingle, this ); 910 911 if ( selection.single() ) { 912 this.createSingle(); 913 } 914 }, 915 916 createSingle: function() { 917 var sidebar = this.sidebar, 918 single = this.options.selection.single(); 919 920 sidebar.set( 'details', new bp.media.view.AvatarDetails({ 921 controller: this.controller, 922 model: single, 923 priority: 80 924 }) ); 925 }, 926 } ); 927 928 bp.media.UploaderInline = bp.media.view.UploaderInline.extend( { 929 initialize:function() { 930 bp.media.view.UploaderInline.prototype.initialize.apply( this, arguments ); 931 932 if ( 'avatar' == bp.media.params.item_type ) { 933 this.on( 'ready', this.customizeUploader, this ); 934 } 935 }, 936 937 customizeUploader:function(){ 938 $( '.upload-ui h3.upload-instructions' ).html( 'Drop your avatar anywhere to upload' ); 939 $( '.upload-ui a.button-hero' ).html( 'Select an image' ); 940 } 941 } ); 942 943 bp.media.view.ToolbarSelect = bp.media.view.Toolbar.Select.extend({ 944 initialize: function() { 945 var options = this.options; 946 /** 947 * call 'initialize' directly on the parent class 948 */ 949 bp.media.view.Toolbar.Select.prototype.initialize.apply( this, arguments ); 950 }, 951 952 refresh: function() { 953 var library = BPmedia.BPattachmentsBrowser._frame.state().get( 'library' ), 954 selection = BPmedia.BPattachmentsBrowser._frame.state().get('selection'); 955 956 if ( -1 == bp.media.params.callback.indexOf( 'http://' ) ) { 957 if ( selection.length > 0 ) { 958 this.get( 'select' ).model.set( 'disabled', false ); 959 } else { 960 this.get( 'select' ).model.set( 'disabled', true ); 961 } 962 } else { 963 this.get( 'select' ).model.set( 'text', 'Ok' ); 964 if ( library.length > 0 ) { 965 this.get( 'select' ).model.set( 'disabled', false ); 966 } else { 967 this.get( 'select' ).model.set( 'disabled', true ); 968 } 969 } 970 }, 971 }); 972 973 BPmedia.BPattachmentsBrowser = _.extend( BPmedia, { 974 frame: function() { 975 if ( this._frame ) 976 return this._frame; 977 978 var states = [new bp.media.controller.bpLibrary()]; 979 980 this._frame = bp.media( { 981 className: 'media-frame no-sidebar', 982 states: states, 983 state: 'bp_library' 984 } ); 985 986 this._frame.on( 'open', this.open ); 987 this._frame.on( 'close', this.close ); 988 this._frame.on( 'router:create:bp_browse', this.createRouter, this ); 989 this._frame.on( 'router:render:bp_browse', this.bpBrowse, this ); 990 this._frame.on( 'content:create:bpbrowse', this.bpBrowseContent, this ); 991 this._frame.on( 'content:create:crop', this.cropAvatar, this ); 992 this._frame.on( 'content:render:bp_upload', this.uploadContent, this ); 993 this._frame.on( 'toolbar:create:bp_select', this.createSelectToolbar, this ); 994 995 this._frame.state( 'bp_library' ).on( 'select', this.select ); 996 997 // Check if one file at a time 998 this._frame.listenToOnce( this._frame.states.get('bp_library').frame.uploader, 'ready', this.oneAtatime, this ); 999 1000 return this._frame; 1001 }, 1002 1003 oneAtatime:function() { 1004 // plupload customs 1 at a time if set so ! 1005 this.uploader.uploader.uploader.bind( 'FilesAdded', function( up, files ) { 1006 // one file at a time ! 1007 if( _wpPluploadSettings.defaults.multi_selection == false && files.length > 1 ) { 1008 var default_error = pluploadL10n.default_error; 1009 pluploadL10n.default_error = bp.media.view.l10n.bp_attachments.files_error; 1010 1011 for ( i in files ) { 1012 this.trigger( 'Error', { 1013 code : 'bp_failed', 1014 file : files[i] 1015 }); 1016 up.removeFile(files[i]); 1017 } 1018 pluploadL10n.default_error = default_error; 1019 } 1020 } ); 1021 }, 1022 1023 createRouter:function( router ) { 1024 router.view = new bp.media.view.Router({ 1025 controller: this._frame 1026 }); 1027 }, 1028 1029 bpBrowse:function( view ) { 1030 1031 if ( 'avatar' == bp.media.params.item_type ) { 1032 view.set({ 1033 bp_upload: { 1034 text: bp.media.view.l10n.bp_attachments.uploadtab, 1035 priority: 20 1036 }, 1037 crop: { 1038 text: bp.media.view.l10n.bp_attachments.croptab, 1039 priority: 40 1040 } 1041 }); 1042 } else { 1043 view.set({ 1044 bp_upload: { 1045 text: bp.media.view.l10n.bp_attachments.uploadtab, 1046 priority: 20 1047 }, 1048 bpbrowse: { 1049 text: bp.media.view.l10n.bp_attachments.managetab, 1050 priority: 40 1051 } 1052 }); 1053 } 1054 1055 }, 1056 1057 bpBrowseContent:function( content ) { 1058 var state = this._frame.state(); 1059 1060 this._frame.$el.removeClass('hide-toolbar'); 1061 1062 // Browse our library of attachments. 1063 content.view = new BPmedia.view.AttachmentsBrowser({ 1064 controller: this._frame, 1065 collection: state.get('library'), 1066 selection: state.get('selection'), 1067 model: state, 1068 sortable: state.get('sortable'), 1069 search: state.get('searchable'), 1070 filters: state.get('filterable'), 1071 display: state.get('displaySettings'), 1072 dragInfo: state.get('dragInfo'), 1073 1074 AttachmentView: state.get('AttachmentView') 1075 }); 1076 }, 1077 1078 cropAvatar: function( content ) { 1079 var state = this._frame.state(); 1080 1081 this._frame.$el.removeClass('hide-toolbar'); 1082 1083 // Browse our library of attachments. 1084 content.view = new BPmedia.view.AvatarCroper({ 1085 controller: this._frame, 1086 collection: state.get('library'), 1087 selection: state.get('selection'), 1088 model: state, 1089 display: state.get('displaySettings'), 1090 dragInfo: state.get('dragInfo') 1091 }); 1092 }, 1093 1094 createSelectToolbar: function( toolbar, options ) { 1095 options = options || this._frame.options.button || {}; 1096 options.controller = this._frame; 1097 1098 if ( 'avatar' == bp.media.params.item_type ) { 1099 toolbar.view = new bp.media.view.Toolbar.Select( options ); 1100 } 1101 1102 if ( ! _.isUndefined( bp.media.params.callback ) && bp.media.params.callback ) { 1103 toolbar.view = new bp.media.view.ToolbarSelect( options ); 1104 } 1105 }, 1106 1107 uploadContent: function() { 1108 1109 if ( 'avatar' == bp.media.params.item_type ) { 1110 this._frame.reset(); 1111 this._frame.state().get('library').reset(); 1112 } 1113 1114 this._frame.$el.removeClass('hide-toolbar'); 1115 this._frame.content.set( new bp.media.UploaderInline({ 1116 controller: this._frame 1117 }) ); 1118 }, 1119 1120 open: function() { 1121 $( '.media-modal' ).css({ 1122 "top": "10%", 1123 "right": "15%", 1124 "bottom": "10%", 1125 "left": "15%" 1126 }); 1127 1128 // Hide screen reader text on front end 1129 if ( ! $( 'body' ).hasClass('wp-admin' ) ) { 1130 $( 'a.media-modal-close .screen-reader-text' ).hide(); 1131 } 1132 }, 1133 1134 close: function() { 1135 $( '.media-modal' ).removeAttr( 'style'); 1136 }, 1137 1138 select: function() { 1139 var settings = bp.media.view.settings.bp_attachments, 1140 selection = this.get( 'selection' ).single(); 1141 1142 $( '.added' ).remove(); 1143 BPmedia.set( selection ); 1144 }, 1145 1146 set: function( attachment ) { 1147 if ( 'avatar' == bp.media.params.item_type ) { 1148 bp.media.post( 'bp_attachments_set_avatar', { 1149 json: true, 1150 object: bp.media.view.settings.bp_attachments.object, 1151 component: bp.media.params.item_component, 1152 avatar_dir: bp.media.view.settings.bp_attachments.avatar_dir, 1153 item_id: bp.media.view.settings.bp_attachments.item_id, 1154 original_file: attachment.get( 'src' ), 1155 crop_w: attachment.get( 'w' ), 1156 crop_h: attachment.get( 'h' ), 1157 crop_x: attachment.get( 'x' ), 1158 crop_y: attachment.get( 'y' ), 1159 nonce: bp.media.params.nonce 1160 }).done( function( html ) { 1161 $( '#' + bp.media.params.item_component + '-avatar', '#bp_' + bp.media.params.item_component + '_avatar' ).html( html ); 1162 $( bp.media.view.settings.bp_attachments.button_id ).hide(); 1163 }); 1164 // reseting the frame 1165 this._frame.reset(); 1166 this._frame.state().get('library').reset(); 1167 1168 } else { 1169 1170 if ( -1 == bp.media.params.callback.indexOf( 'http://' ) ) { 1171 bp.media.post( bp.media.params.callback, { 1172 json: true, 1173 id: attachment.get('id'), 1174 object: bp.media.view.settings.bp_attachments.object, 1175 component: bp.media.params.item_component, 1176 item_id: bp.media.view.settings.bp_attachments.item_id, 1177 nonce: bp.media.params.nonce 1178 }).done( function( html ) { 1179 $( bp.media.params.callback_id ).html( html ); 1180 }); 1181 } else { 1182 window.location.href = bp.media.params.callback; 1183 } 1184 } 1185 }, 1186 1187 deleteAvatar: function() { 1188 bp.media.post( 'bp_attachments_delete_avatar', { 1189 json: true, 1190 object: bp.media.view.settings.bp_attachments.object, 1191 avatar_dir: bp.media.view.settings.bp_attachments.avatar_dir, 1192 component: bp.media.params.item_component, 1193 item_id: bp.media.view.settings.bp_attachments.item_id, 1194 nonce: bp.media.params.nonce 1195 }).done( function( result ) { 1196 1197 if ( 1 == result ) { 1198 $( '#' + bp.media.params.item_component + '-avatar img' ).remove(); 1199 $( '#' + bp.media.params.item_component + '-avatar p' ).remove(); 1200 $( bp.media.view.settings.bp_attachments.button_id ).show(); 1201 } 1202 1203 }); 1204 }, 1205 1206 init: function() { 1207 1208 if ( 'avatar' == bp.media.params.item_type ) { 1209 // Avatar 1210 if ( $( '#attachment-upload-form' ).length ) { 1211 $( '#attachment-upload-form' ).remove(); 1212 } 1213 1214 if ( $( '#create-group-form p#attachment-upload' ).length ) { 1215 $( '#create-group-form p#attachment-upload' ).remove(); 1216 } 1217 1218 if ( ! $( '#remove-' + bp.media.params.item_component + '-avatar' ).length ) { 1219 $( bp.media.view.settings.bp_attachments.button_id ).show(); 1220 } 1221 $( '#' + bp.media.params.item_component + '-avatar' ).on( 'click', 'a', function(e) { 1222 e.preventDefault(); 1223 1224 BPmedia.BPattachmentsBrowser.deleteAvatar(); 1225 }); 1226 } else { 1227 if ( $( '#attachment-upload-form' ).length ) { 1228 $( '#attachment-upload-form' ).remove(); 1229 $( bp.media.view.settings.bp_attachments.button_id ).show(); 1230 } 1231 } 1232 1233 $( bp.media.view.settings.bp_attachments.button_id ).on( 'click', 'a', function( e ) { 1234 e.preventDefault(); 1235 1236 BPmedia.BPattachmentsBrowser.frame().open(); 1237 }); 1238 } 1239 } ); 1240 1241 // Attachments & Avatars 1242 $( BPmedia.BPattachmentsBrowser.init ); 1243 1244 } )( jQuery ); -
src/bp-core/admin/bp-core-components.php
diff --git src/bp-core/admin/bp-core-components.php src/bp-core/admin/bp-core-components.php index f05d285..6e05930 100644
function bp_core_admin_components_settings_handler() { 255 255 bp_core_install( $bp->active_components ); 256 256 bp_core_add_page_mappings( $bp->active_components ); 257 257 bp_update_option( 'bp-active-components', $bp->active_components ); 258 259 /** 260 * Disable avatar uploads if the Attachments component has been deactivated 261 * 262 * As src/bp-templates/bp-legacy/buddypress/members/single/profile/change-avatar.php 263 * is directly checking this option, we are a bit forced to update this option in case 264 * the attachments component is not active 265 */ 266 if ( empty( $bp->active_components['attachments'] ) ) { 267 bp_update_option( 'bp-disable-avatar-uploads', 1 ); 268 269 // As Only avatars are managed so far, restore the option if Attachments component is activated 270 } else { 271 bp_update_option( 'bp-disable-avatar-uploads', 0 ); 272 } 258 273 } 259 274 260 275 // Where are we redirecting to? … … function bp_core_admin_get_components( $type = 'all' ) { 395 410 'blogs' => array( 396 411 'title' => __( 'Site Tracking', 'buddypress' ), 397 412 'description' => __( 'Record activity for new posts and comments from your site.', 'buddypress' ) 398 ) 413 ), 414 'attachments' => array( 415 'title' => __( 'Attachments', 'buddypress' ), 416 'description' => __( 'Utility to manage your users attachments such as avatars', 'buddypress' ) 417 ), 399 418 ); 400 419 401 420 -
src/bp-core/admin/bp-core-settings.php
diff --git src/bp-core/admin/bp-core-settings.php src/bp-core/admin/bp-core-settings.php index 71f8f33..11834bc 100644
function bp_admin_setting_callback_bbpress_configuration() { 218 218 <?php 219 219 } 220 220 221 /** Attachments ***************************************************************/ 222 223 /** 224 * Attachments settings section description for the settings page 225 * 226 * @since BuddyPress (2.2.0) 227 */ 228 function bp_admin_setting_callback_attachments_section() { } 229 221 230 /** Settings Page *************************************************************/ 222 231 223 232 /** -
src/bp-core/admin/css/common.css
diff --git src/bp-core/admin/css/common.css src/bp-core/admin/css/common.css index 0899ce7..fd85770 100644
body.branch-3-7 #adminmenu li.toplevel_page_bp-general-settings .wp-menu-image { 237 237 content: "\f454"; 238 238 } 239 239 240 .settings_page_bp-components tr.attachments td.plugin-title span:before { 241 content: "\f128"; 242 } 243 240 244 /* Settings - Legacy (< WP 3.8) */ 241 245 body.branch-3-6.settings_page_bp-components tr.activity td.plugin-title span:before, 242 246 body.branch-3-6.settings_page_bp-components tr.notifications td.plugin-title span:before, -
src/bp-core/bp-core-admin.php
diff --git src/bp-core/bp-core-admin.php src/bp-core/bp-core-admin.php index 217eb08..7f65e67 100644
class BP_Admin { 336 336 // Add the main section 337 337 add_settings_section( 'bp_xprofile', _x( 'Profile Settings', 'BuddyPress setting tab', 'buddypress' ), 'bp_admin_setting_callback_xprofile_section', 'buddypress' ); 338 338 339 $avatar_setting = 'bp_xprofile';340 341 339 // Profile sync setting 342 340 add_settings_field( 'bp-disable-profile-sync', __( 'Profile Syncing', 'buddypress' ), 'bp_admin_setting_callback_profile_sync', 'buddypress', 'bp_xprofile' ); 343 341 register_setting ( 'buddypress', 'bp-disable-profile-sync', 'intval' ); … … class BP_Admin { 350 348 // Add the main section 351 349 add_settings_section( 'bp_groups', __( 'Groups Settings', 'buddypress' ), 'bp_admin_setting_callback_groups_section', 'buddypress' ); 352 350 353 if ( empty( $avatar_setting ) )354 $avatar_setting = 'bp_groups';355 356 351 // Allow subscriptions setting 357 352 add_settings_field( 'bp_restrict_group_creation', __( 'Group Creation', 'buddypress' ), 'bp_admin_setting_callback_group_creation', 'buddypress', 'bp_groups' ); 358 353 register_setting ( 'buddypress', 'bp_restrict_group_creation', 'intval' ); … … class BP_Admin { 392 387 } 393 388 } 394 389 395 /** Avatar upload for users or groups ************************************/ 390 /** Attachments section ***********************************************/ 391 392 if ( bp_is_active( 'attachments' ) ) { 393 // Add the main section 394 add_settings_section( 'bp_attachments', __( 'Attachments Settings', 'buddypress' ), 'bp_admin_setting_callback_attachments_section', 'buddypress' ); 396 395 397 if ( ! empty( $avatar_setting ) ) {398 396 // Allow avatar uploads 399 add_settings_field( 'bp-disable-avatar-uploads', __( 'Profile Photo Uploads', 'buddypress' ), 'bp_admin_setting_callback_avatar_uploads', 'buddypress', $avatar_setting);400 register_setting ( 'buddypress', 'bp-disable-avatar-uploads', 'intval' );397 add_settings_field( 'bp-disable-avatar-uploads', __( 'Profile Photo Uploads', 'buddypress' ), 'bp_admin_setting_callback_avatar_uploads', 'buddypress', 'bp_attachments' ); 398 register_setting ( 'buddypress', 'bp-disable-avatar-uploads', 'intval' ); 401 399 } 402 400 } 403 401 … … class BP_Admin { 512 510 </a> 513 511 </h2> 514 512 515 <?php if ( $is_new_install ) : ?> 513 <?php if ( $is_new_install ) : ?> 516 514 517 515 <div id="welcome-panel" class="welcome-panel"> 518 516 <div class="welcome-panel-content"> … … class BP_Admin { 521 519 <div class="welcome-panel-column"> 522 520 <h4><?php _e( 'Configure Buddypress', 'buddypress' ); ?></h4> 523 521 <ul> 524 <li><?php printf( 522 <li><?php printf( 525 523 '<a href="%s" class="welcome-icon welcome-edit-page">' . __( 'Set Up Components', 'buddypress' ) . '</a>', bp_get_admin_url( add_query_arg( array( 'page' => 'bp-components' ), $this->settings_page ) ) 526 524 ); ?></li> 527 <li><?php printf( 525 <li><?php printf( 528 526 '<a href="%s" class="welcome-icon welcome-edit-page">' . __( 'Assign Components to Pages', 'buddypress' ) . '</a>', bp_get_admin_url( add_query_arg( array( 'page' => 'bp-page-settings' ), $this->settings_page ) ) 529 527 ); ?></li> 530 528 <li><?php printf( … … class BP_Admin { 552 550 </div> 553 551 <div class="welcome-panel-column welcome-panel-last"> 554 552 <h4><?php _e( 'Community and Support', 'buddypress' ); ?></h4> 555 <p class="welcome-icon welcome-learn-more" style="margin-right:10px"><?php _e( 'Looking for help? The <a href="http://codex.buddypress.org/">BuddyPress Codex</a> has you covered.', 'buddypress' ) ?></p> 553 <p class="welcome-icon welcome-learn-more" style="margin-right:10px"><?php _e( 'Looking for help? The <a href="http://codex.buddypress.org/">BuddyPress Codex</a> has you covered.', 'buddypress' ) ?></p> 556 554 <p class="welcome-icon welcome-learn-more" style="margin-right:10px"><?php _e( 'Can’t find what you need? Stop by <a href="http://buddypress.org/support/">our support forums</a>, where active BuddyPress users and developers are waiting to share tips and more.', 'buddypress' ) ?></p> 557 555 </div> 558 556 </div> … … class BP_Admin { 649 647 _e( 'When making searches with <code>BP_User_Query</code>, a new <code>search_wildcard</code> parameter gives you finer control over how the search SQL is constructed.', 'buddypress' ); 650 648 ?> 651 649 </li> 652 650 653 651 654 652 <li><?php printf( __( '<a href="%s">…and lots more!</a>', 'buddypress' ), 'https://codex.buddypress.org/releases/version-2-1' ); ?></li> 655 653 </ul> -
src/bp-core/bp-core-avatars.php
diff --git src/bp-core/bp-core-avatars.php src/bp-core/bp-core-avatars.php index 65c516e..44e3ae6 100644
function bp_core_set_avatar_constants() { 26 26 if ( !defined( 'BP_AVATAR_FULL_HEIGHT' ) ) 27 27 define( 'BP_AVATAR_FULL_HEIGHT', 150 ); 28 28 29 if ( !defined( 'BP_AVATAR_ORIGINAL_MAX_WIDTH' ) )30 define( 'BP_AVATAR_ORIGINAL_MAX_WIDTH', 450 );31 32 if ( !defined( 'BP_AVATAR_ORIGINAL_MAX_FILESIZE' ) ) {33 34 if ( !isset( $bp->site_options['fileupload_maxk'] ) ) {35 define( 'BP_AVATAR_ORIGINAL_MAX_FILESIZE', 5120000 ); // 5mb36 } else {37 define( 'BP_AVATAR_ORIGINAL_MAX_FILESIZE', $bp->site_options['fileupload_maxk'] * 1024 );38 }39 }40 41 29 if ( ! defined( 'BP_SHOW_AVATARS' ) ) { 42 30 define( 'BP_SHOW_AVATARS', bp_get_option( 'show_avatars' ) ); 43 31 } … … function bp_core_set_avatar_globals() { 62 50 $bp->avatar->full->width = BP_AVATAR_FULL_WIDTH; 63 51 $bp->avatar->full->height = BP_AVATAR_FULL_HEIGHT; 64 52 65 // Upload maximums66 $bp->avatar->original_max_width = BP_AVATAR_ORIGINAL_MAX_WIDTH;67 $bp->avatar->original_max_filesize = BP_AVATAR_ORIGINAL_MAX_FILESIZE;68 69 53 // Defaults 70 54 $bp->avatar->thumb->default = bp_core_avatar_default_thumb(); 71 55 $bp->avatar->full->default = bp_core_avatar_default(); 72 56 73 // These have to be set on page load in order to avoid infinite filter loops at runtime74 $bp->avatar->upload_path = bp_core_avatar_upload_path();75 $bp->avatar->url = bp_core_avatar_url();76 77 57 // Cache the root blog's show_avatars setting, to avoid unnecessary 78 58 // calls to switch_to_blog() 79 59 $bp->avatar->show_avatars = (bool) BP_SHOW_AVATARS; 80 60 81 // Backpat for pre-1.582 if ( ! defined( 'BP_AVATAR_UPLOAD_PATH' ) )83 define( 'BP_AVATAR_UPLOAD_PATH', $bp->avatar->upload_path );84 85 // Backpat for pre-1.586 if ( ! defined( 'BP_AVATAR_URL' ) )87 define( 'BP_AVATAR_URL', $bp->avatar->url );88 89 61 do_action( 'bp_core_set_avatar_globals' ); 90 62 } 91 63 add_action( 'bp_setup_globals', 'bp_core_set_avatar_globals' ); … … function bp_core_fetch_avatar( $args = '' ) { 200 172 'title' => '', 201 173 ) ); 202 174 175 $avatar = (object) $params; 176 $avatar->folder_url = ''; 177 $avatar->folder_dir = ''; 178 $avatar->url = ''; 179 203 180 /** Set item_id ***********************************************************/ 204 181 205 if ( empty( $ params['item_id']) ) {182 if ( empty( $avatar->item_id ) ) { 206 183 207 switch ( $ params['object']) {184 switch ( $avatar->object ) { 208 185 209 186 case 'blog' : 210 $ params['item_id']= $current_blog->id;187 $avatar->item_id = $current_blog->id; 211 188 break; 212 189 213 190 case 'group' : 214 191 if ( bp_is_active( 'groups' ) ) { 215 $ params['item_id']= $bp->groups->current_group->id;192 $avatar->item_id = $bp->groups->current_group->id; 216 193 } else { 217 $ params['item_id']= false;194 $avatar->item_id = false; 218 195 } 219 196 220 197 break; 221 198 222 199 case 'user' : 223 200 default : 224 $ params['item_id']= bp_displayed_user_id();201 $avatar->item_id = bp_displayed_user_id(); 225 202 break; 226 203 } 227 204 228 $ params['item_id'] = apply_filters( 'bp_core_avatar_item_id', $params['item_id'], $params['object'], $params);205 $avatar->item_id = apply_filters( 'bp_core_avatar_item_id', $avatar->item_id, $avatar->object, $avatar ); 229 206 230 if ( empty( $ params['item_id']) ) {207 if ( empty( $avatar->item_id ) ) { 231 208 return false; 232 209 } 233 210 } 234 211 235 212 /** Set avatar_dir ********************************************************/ 236 213 237 if ( empty( $ params['avatar_dir']) ) {214 if ( empty( $avatar->avatar_dir ) ) { 238 215 239 switch ( $ params['object']) {216 switch ( $avatar->object ) { 240 217 241 218 case 'blog' : 242 $ params['avatar_dir'] = 'blog-avatars';219 $avatar->avatar_dir = 'avatar_blog'; 243 220 break; 244 221 245 222 case 'group' : 246 223 if ( bp_is_active( 'groups' ) ) { 247 $ params['avatar_dir'] = 'group-avatars';224 $avatar->avatar_dir = 'avatar_group'; 248 225 } else { 249 $ params['avatar_dir']= false;226 $avatar->avatar_dir = false; 250 227 } 251 228 252 229 break; 253 230 254 231 case 'user' : 255 232 default : 256 $ params['avatar_dir'] = 'avatars';233 $avatar->avatar_dir = 'avatar_user'; 257 234 break; 258 235 } 259 236 260 $ params['avatar_dir'] = apply_filters( 'bp_core_avatar_dir', $params['avatar_dir'], $params['object'], $params);237 $avatar->avatar_dir = apply_filters( 'bp_core_avatar_dir', $avatar->avatar_dir, $avatar->object, $avatar ); 261 238 262 if ( empty( $ params['avatar_dir']) ) {239 if ( empty( $avatar->avatar_dir ) ) { 263 240 return false; 264 241 } 265 242 } 266 243 267 244 /** <img> alt *************************************************************/ 268 245 269 if ( false !== strpos( $ params['alt'], '%s' ) || false !== strpos( $params['alt'], '%1$s' ) ) {246 if ( false !== strpos( $avatar->alt, '%s' ) || false !== strpos( $avatar->alt, '%1$s' ) ) { 270 247 271 switch ( $ params['object']) {248 switch ( $avatar->object ) { 272 249 273 250 case 'blog' : 274 $item_name = get_blog_option( $ params['item_id'], 'blogname' );251 $item_name = get_blog_option( $avatar->item_id, 'blogname' ); 275 252 break; 276 253 277 254 case 'group' : 278 $item_name = bp_get_group_name( groups_get_group( array( 'group_id' => $ params['item_id']) ) );255 $item_name = bp_get_group_name( groups_get_group( array( 'group_id' => $avatar->item_id ) ) ); 279 256 break; 280 257 281 258 case 'user' : 282 259 default : 283 $item_name = bp_core_get_user_displayname( $ params['item_id']);260 $item_name = bp_core_get_user_displayname( $avatar->item_id ); 284 261 break; 285 262 } 286 263 287 $item_name = apply_filters( 'bp_core_avatar_alt', $item_name, $ params['item_id'], $params['object'], $params);288 $ params['alt'] = sprintf( $params['alt'], $item_name );264 $item_name = apply_filters( 'bp_core_avatar_alt', $item_name, $avatar->item_id, $avatar->object, $avatar ); 265 $avatar->alt = sprintf( $avatar->alt, $item_name ); 289 266 } 290 267 291 268 /** Sanity Checks *********************************************************/ 292 269 293 270 // Get a fallback for the 'alt' parameter, create html output 294 if ( empty( $ params['alt']) ) {295 $ params['alt']= __( 'Profile Photo', 'buddypress' );271 if ( empty( $avatar->alt ) ) { 272 $avatar->alt = __( 'Profile Photo', 'buddypress' ); 296 273 } 297 $html_alt = ' alt="' . esc_attr( $ params['alt']) . '"';274 $html_alt = ' alt="' . esc_attr( $avatar->alt ) . '"'; 298 275 299 276 // Filter image title and create html string 300 277 $html_title = ''; 301 $ params['title'] = apply_filters( 'bp_core_avatar_title', $params['title'], $params['item_id'], $params['object'], $params);278 $avatar->title = apply_filters( 'bp_core_avatar_title', $avatar->title, $avatar->item_id, $avatar->object, $avatar ); 302 279 303 if ( ! empty( $ params['title']) ) {304 $html_title = ' title="' . esc_attr( $ params['title']) . '"';280 if ( ! empty( $avatar->title ) ) { 281 $html_title = ' title="' . esc_attr( $avatar->title ) . '"'; 305 282 } 306 283 307 284 // Set CSS ID and create html string 308 285 $html_css_id = ''; 309 $ params['css_id'] = apply_filters( 'bp_core_css_id', $params['css_id'], $params['item_id'], $params['object'], $params);286 $avatar->css_id = apply_filters( 'bp_core_css_id', $avatar->css_id, $avatar->item_id, $avatar->object, $avatar ); 310 287 311 if ( ! empty( $ params['css_id']) ) {312 $html_css_id = ' id="' . esc_attr( $ params['css_id']) . '"';288 if ( ! empty( $avatar->css_id ) ) { 289 $html_css_id = ' id="' . esc_attr( $avatar->css_id ) . '"'; 313 290 } 314 291 315 292 // Set image width 316 if ( false !== $ params['width']) {293 if ( false !== $avatar->width ) { 317 294 // Width has been specified. No modification necessary. 318 } else if ( 'thumb' == $ params['type']) {319 $ params['width']= bp_core_avatar_thumb_width();295 } else if ( 'thumb' == $avatar->type ) { 296 $avatar->width = bp_core_avatar_thumb_width(); 320 297 } else { 321 $ params['width']= bp_core_avatar_full_width();298 $avatar->width = bp_core_avatar_full_width(); 322 299 } 323 $html_width = ' width="' . $ params['width']. '"';300 $html_width = ' width="' . $avatar->width . '"'; 324 301 325 302 // Set image height 326 if ( false !== $ params['height']) {303 if ( false !== $avatar->height ) { 327 304 // Height has been specified. No modification necessary. 328 } else if ( 'thumb' == $ params['type']) {329 $ params['height']= bp_core_avatar_thumb_height();305 } else if ( 'thumb' == $avatar->type ) { 306 $avatar->height = bp_core_avatar_thumb_height(); 330 307 } else { 331 $ params['height']= bp_core_avatar_full_height();308 $avatar->height = bp_core_avatar_full_height(); 332 309 } 333 $html_height = ' height="' . $ params['height']. '"';310 $html_height = ' height="' . $avatar->height . '"'; 334 311 335 312 // Create CSS class html string 336 $params['class'] = apply_filters( 'bp_core_avatar_class', $params['class'], $params['item_id'], $params['object'], $params ); 337 $html_class = ' class="' . sanitize_html_class( $params['class'] ) . ' ' . sanitize_html_class( $params['object'] . '-' . $params['item_id'] . '-avatar' ) . ' ' . sanitize_html_class( 'avatar-' . $params['width'] ) . ' photo"'; 338 339 // Set img URL and DIR based on prepopulated constants 340 $avatar_loc = new stdClass(); 341 $avatar_loc->path = trailingslashit( bp_core_avatar_upload_path() ); 342 $avatar_loc->url = trailingslashit( bp_core_avatar_url() ); 343 344 $avatar_loc->dir = trailingslashit( $params['avatar_dir'] ); 345 $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'] ); 346 $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'] ); 313 $avatar->class = apply_filters( 'bp_core_avatar_class', $avatar->class, $avatar->item_id, $avatar->object, $avatar ); 314 $html_class = ' class="' . sanitize_html_class( $avatar->class ) . ' ' . sanitize_html_class( $avatar->object . '-' . $avatar->item_id . '-avatar' ) . ' ' . sanitize_html_class( 'avatar-' . $avatar->width ) . ' photo"'; 347 315 348 316 /** 349 * Look for uploaded avatar first. Use it if it exists.350 * Set the file names to search for, to select the full size351 * or thumbnail image.317 * Do no use this filter, for internal use only. 318 * The Attachments component if active will check 319 * for a local avatar 352 320 */ 353 $avatar_size = ( 'full' == $params['type'] ) ? '-bpfull' : '-bpthumb'; 354 $legacy_user_avatar_name = ( 'full' == $params['type'] ) ? '-avatar2' : '-avatar1'; 355 $legacy_group_avatar_name = ( 'full' == $params['type'] ) ? '-groupavatar-full' : '-groupavatar-thumb'; 356 357 // Check for directory 358 if ( file_exists( $avatar_folder_dir ) ) { 359 360 // Open directory 361 if ( $av_dir = opendir( $avatar_folder_dir ) ) { 362 363 // Stash files in an array once to check for one that matches 364 $avatar_files = array(); 365 while ( false !== ( $avatar_file = readdir( $av_dir ) ) ) { 366 // Only add files to the array (skip directories) 367 if ( 2 < strlen( $avatar_file ) ) { 368 $avatar_files[] = $avatar_file; 369 } 370 } 371 372 // Check for array 373 if ( 0 < count( $avatar_files ) ) { 374 375 // Check for current avatar 376 foreach( $avatar_files as $key => $value ) { 377 if ( strpos ( $value, $avatar_size )!== false ) { 378 $avatar_url = $avatar_folder_url . '/' . $avatar_files[$key]; 379 } 380 } 381 382 // Legacy avatar check 383 if ( !isset( $avatar_url ) ) { 384 foreach( $avatar_files as $key => $value ) { 385 if ( strpos ( $value, $legacy_user_avatar_name )!== false ) { 386 $avatar_url = $avatar_folder_url . '/' . $avatar_files[$key]; 387 } 388 } 389 390 // Legacy group avatar check 391 if ( !isset( $avatar_url ) ) { 392 foreach( $avatar_files as $key => $value ) { 393 if ( strpos ( $value, $legacy_group_avatar_name )!== false ) { 394 $avatar_url = $avatar_folder_url . '/' . $avatar_files[$key]; 395 } 396 } 397 } 398 } 399 } 400 } 401 402 // Close the avatar directory 403 closedir( $av_dir ); 321 $avatar = apply_filters( 'bp_core_avatar_local_data', $avatar ); 404 322 405 406 if ( isset( $avatar_url ) ) {323 // If we found a locally uploaded avatar 324 if ( ! empty( $avatar->url ) ) { 407 325 408 409 if ( true === $params['html']) {410 return apply_filters( 'bp_core_fetch_avatar', '<img src="' . $avatar_url . '"' . $html_class . $html_css_id . $html_width . $html_height . $html_alt . $html_title . ' />', $params, $params['item_id'], $params['avatar_dir'], $html_css_id, $html_width, $html_height, $avatar_folder_url, $avatar_folder_dir );326 // Return it wrapped in an <img> element 327 if ( true === $avatar->html ) { 328 return apply_filters( 'bp_core_fetch_avatar', '<img src="' . $avatar->url . '"' . $html_class . $html_css_id . $html_width . $html_height . $html_alt . $html_title . ' />', $params, $avatar->item_id, $avatar->avatar_dir, $html_css_id, $html_width, $html_height, $avatar->folder_url, $avatar->folder_dir ); 411 329 412 // ...or only the URL 413 } else { 414 return apply_filters( 'bp_core_fetch_avatar_url', $avatar_url, $params ); 415 } 330 // ...or only the URL 331 } else { 332 return apply_filters( 'bp_core_fetch_avatar_url', $avatar->url, $params ); 416 333 } 417 334 } 418 335 419 336 // If no avatars could be found, try to display a gravatar 420 337 421 338 // Skips gravatar check if $params['no_grav'] is passed 422 if ( ! apply_filters( 'bp_core_fetch_avatar_no_grav', $ params['no_grav'], $params) ) {339 if ( ! apply_filters( 'bp_core_fetch_avatar_no_grav', $avatar->no_grav, $avatar ) ) { 423 340 424 341 // Set gravatar type 425 if ( empty( $bp->grav_default->{$ params['object']} ) ) {342 if ( empty( $bp->grav_default->{$avatar->object} ) ) { 426 343 $default_grav = 'wavatar'; 427 } else if ( 'mystery' == $bp->grav_default->{$ params['object']} ) {428 $default_grav = apply_filters( 'bp_core_mysteryman_src', 'mm', $ params['width']);344 } else if ( 'mystery' == $bp->grav_default->{$avatar->object} ) { 345 $default_grav = apply_filters( 'bp_core_mysteryman_src', 'mm', $avatar->width ); 429 346 } else { 430 $default_grav = $bp->grav_default->{$ params['object']};347 $default_grav = $bp->grav_default->{$avatar->object}; 431 348 } 432 349 433 350 // Set gravatar object 434 if ( empty( $ params['email']) ) {435 if ( 'user' == $ params['object']) {436 $ params['email'] = bp_core_get_user_email( $params['item_id']);437 } else if ( 'group' == $ params['object'] || 'blog' == $params['object']) {438 $ params['email'] = $params['item_id'] . '-' . $params['object']. '@' . bp_get_root_domain();351 if ( empty( $avatar->email ) ) { 352 if ( 'user' == $avatar->object ) { 353 $avatar->email = bp_core_get_user_email( $avatar->item_id ); 354 } else if ( 'group' == $avatar->object || 'blog' == $avatar->object ) { 355 $avatar->email = $avatar->item_id . '-' . $avatar->object . '@' . bp_get_root_domain(); 439 356 } 440 357 } 441 358 … … function bp_core_fetch_avatar( $args = '' ) { 446 363 } 447 364 448 365 // Filter gravatar vars 449 $ params['email'] = apply_filters( 'bp_core_gravatar_email', $params['email'], $params['item_id'], $params['object']);450 $gravatar = apply_filters( 'bp_gravatar_url', $host ) . md5( strtolower( $ params['email'] ) ) . '?d=' . $default_grav . '&s=' . $params['width'];366 $avatar->email = apply_filters( 'bp_core_gravatar_email', $avatar->email, $avatar->item_id, $avatar->object ); 367 $gravatar = apply_filters( 'bp_gravatar_url', $host ) . md5( strtolower( $avatar->email ) ) . '?d=' . $default_grav . '&s=' . $avatar->width; 451 368 452 369 // Gravatar rating; http://bit.ly/89QxZA 453 370 $rating = get_option( 'avatar_rating' ); … … function bp_core_fetch_avatar( $args = '' ) { 457 374 458 375 // No avatar was found, and we've been told not to use a gravatar. 459 376 } else { 460 $gravatar = apply_filters( 'bp_core_default_avatar_' . $ params['object'], bp_core_avatar_default( 'local' ), $params);377 $gravatar = apply_filters( 'bp_core_default_avatar_' . $avatar->object, bp_core_avatar_default( 'local' ), $avatar ); 461 378 } 462 379 463 if ( true === $ params['html']) {464 return apply_filters( 'bp_core_fetch_avatar', '<img src="' . $gravatar . '"' . $html_css_id . $html_class . $html_width . $html_height . $html_alt . $html_title . ' />', $params, $ params['item_id'], $params['avatar_dir'], $html_css_id, $html_width, $html_height, $avatar_folder_url, $avatar_folder_dir );380 if ( true === $avatar->html ) { 381 return apply_filters( 'bp_core_fetch_avatar', '<img src="' . $gravatar . '"' . $html_css_id . $html_class . $html_width . $html_height . $html_alt . $html_title . ' />', $params, $avatar->item_id, $avatar->avatar_dir, $html_css_id, $html_width, $html_height, $avatar->folder_url, $avatar->folder_dir ); 465 382 } else { 466 383 return apply_filters( 'bp_core_fetch_avatar_url', $gravatar, $params ); 467 384 } 468 385 } 469 386 470 387 /** 471 * Delete an existing avatar.472 *473 * @param array $args {474 * Array of function parameters.475 * @type bool|int $item_id ID of the item whose avatar you're deleting.476 * Defaults to the current item of type $object.477 * @type string $object Object type of the item whose avatar you're478 * deleting. 'user', 'group', 'blog', or custom. Default: 'user'.479 * @type bool|string $avatar_dir Subdirectory where avatar is located.480 * Default: false, which falls back on the default location481 * corresponding to the $object.482 * }483 * @return bool True on success, false on failure.484 */485 function bp_core_delete_existing_avatar( $args = '' ) {486 487 $defaults = array(488 'item_id' => false,489 'object' => 'user', // user OR group OR blog OR custom type (if you use filters)490 'avatar_dir' => false491 );492 493 $args = wp_parse_args( $args, $defaults );494 extract( $args, EXTR_SKIP );495 496 if ( empty( $item_id ) ) {497 if ( 'user' == $object )498 $item_id = bp_displayed_user_id();499 else if ( 'group' == $object )500 $item_id = buddypress()->groups->current_group->id;501 else if ( 'blog' == $object )502 $item_id = $current_blog->id;503 504 $item_id = apply_filters( 'bp_core_avatar_item_id', $item_id, $object );505 506 if ( !$item_id ) return false;507 }508 509 if ( empty( $avatar_dir ) ) {510 if ( 'user' == $object )511 $avatar_dir = 'avatars';512 else if ( 'group' == $object )513 $avatar_dir = 'group-avatars';514 else if ( 'blog' == $object )515 $avatar_dir = 'blog-avatars';516 517 $avatar_dir = apply_filters( 'bp_core_avatar_dir', $avatar_dir, $object );518 519 if ( !$avatar_dir ) return false;520 }521 522 $avatar_folder_dir = apply_filters( 'bp_core_avatar_folder_dir', bp_core_avatar_upload_path() . '/' . $avatar_dir . '/' . $item_id, $item_id, $object, $avatar_dir );523 524 if ( !file_exists( $avatar_folder_dir ) )525 return false;526 527 if ( $av_dir = opendir( $avatar_folder_dir ) ) {528 while ( false !== ( $avatar_file = readdir($av_dir) ) ) {529 if ( ( preg_match( "/-bpfull/", $avatar_file ) || preg_match( "/-bpthumb/", $avatar_file ) ) && '.' != $avatar_file && '..' != $avatar_file )530 @unlink( $avatar_folder_dir . '/' . $avatar_file );531 }532 }533 closedir($av_dir);534 535 @rmdir( $avatar_folder_dir );536 537 do_action( 'bp_core_delete_existing_avatar', $args );538 539 return true;540 }541 542 /**543 * Handle avatar uploading.544 *545 * The functions starts off by checking that the file has been uploaded546 * properly using bp_core_check_avatar_upload(). It then checks that the file547 * size is within limits, and that it has an accepted file extension (jpg, gif,548 * png). If everything checks out, crop the image and move it to its real549 * location.550 *551 * @see bp_core_check_avatar_upload()552 * @see bp_core_check_avatar_type()553 *554 * @param array $file The appropriate entry the from $_FILES superglobal.555 * @param string $upload_dir_filter A filter to be applied to 'upload_dir'.556 * @return bool True on success, false on failure.557 */558 function bp_core_avatar_handle_upload( $file, $upload_dir_filter ) {559 560 /***561 * You may want to hook into this filter if you want to override this function.562 * Make sure you return false.563 */564 if ( !apply_filters( 'bp_core_pre_avatar_handle_upload', true, $file, $upload_dir_filter ) )565 return true;566 567 require_once( ABSPATH . '/wp-admin/includes/file.php' );568 569 $uploadErrors = array(570 0 => __( 'The image was uploaded successfully', 'buddypress' ),571 1 => __( 'The image exceeds the maximum allowed file size of: ', 'buddypress' ) . size_format( bp_core_avatar_original_max_filesize() ),572 2 => __( 'The image exceeds the maximum allowed file size of: ', 'buddypress' ) . size_format( bp_core_avatar_original_max_filesize() ),573 3 => __( 'The uploaded file was only partially uploaded.', 'buddypress' ),574 4 => __( 'The image was not uploaded.', 'buddypress' ),575 6 => __( 'Missing a temporary folder.', 'buddypress' )576 );577 578 if ( ! bp_core_check_avatar_upload( $file ) ) {579 bp_core_add_message( sprintf( __( 'Your upload failed, please try again. Error was: %s', 'buddypress' ), $uploadErrors[$file['file']['error']] ), 'error' );580 return false;581 }582 583 if ( ! bp_core_check_avatar_size( $file ) ) {584 bp_core_add_message( sprintf( __( 'The file you uploaded is too big. Please upload a file under %s', 'buddypress' ), size_format( bp_core_avatar_original_max_filesize() ) ), 'error' );585 return false;586 }587 588 if ( ! bp_core_check_avatar_type( $file ) ) {589 bp_core_add_message( __( 'Please upload only JPG, GIF or PNG photos.', 'buddypress' ), 'error' );590 return false;591 }592 593 // Filter the upload location594 add_filter( 'upload_dir', $upload_dir_filter, 10, 0 );595 596 $bp = buddypress();597 598 $bp->avatar_admin->original = wp_handle_upload( $file['file'], array( 'action'=> 'bp_avatar_upload' ) );599 600 // Remove the upload_dir filter, so that other upload URLs on the page601 // don't break602 remove_filter( 'upload_dir', $upload_dir_filter, 10, 0 );603 604 // Move the file to the correct upload location.605 if ( !empty( $bp->avatar_admin->original['error'] ) ) {606 bp_core_add_message( sprintf( __( 'Upload Failed! Error was: %s', 'buddypress' ), $bp->avatar_admin->original['error'] ), 'error' );607 return false;608 }609 610 // Get image size611 $size = @getimagesize( $bp->avatar_admin->original['file'] );612 $error = false;613 614 // Check image size and shrink if too large615 if ( $size[0] > bp_core_avatar_original_max_width() ) {616 $editor = wp_get_image_editor( $bp->avatar_admin->original['file'] );617 618 if ( ! is_wp_error( $editor ) ) {619 $editor->set_quality( 100 );620 621 $resized = $editor->resize( bp_core_avatar_original_max_width(), bp_core_avatar_original_max_width(), false );622 if ( ! is_wp_error( $resized ) ) {623 $thumb = $editor->save( $editor->generate_filename() );624 } else {625 $error = $resized;626 }627 628 // Check for thumbnail creation errors629 if ( false === $error && is_wp_error( $thumb ) ) {630 $error = $thumb;631 }632 633 // Thumbnail is good so proceed634 if ( false === $error ) {635 $bp->avatar_admin->resized = $thumb;636 }637 638 } else {639 $error = $editor;640 }641 642 if ( false !== $error ) {643 bp_core_add_message( sprintf( __( 'Upload Failed! Error was: %s', 'buddypress' ), $error->get_error_message() ), 'error' );644 return false;645 }646 }647 648 if ( ! isset( $bp->avatar_admin->image ) )649 $bp->avatar_admin->image = new stdClass();650 651 // We only want to handle one image after resize.652 if ( empty( $bp->avatar_admin->resized ) ) {653 $bp->avatar_admin->image->dir = str_replace( bp_core_avatar_upload_path(), '', $bp->avatar_admin->original['file'] );654 } else {655 $bp->avatar_admin->image->dir = str_replace( bp_core_avatar_upload_path(), '', $bp->avatar_admin->resized['path'] );656 @unlink( $bp->avatar_admin->original['file'] );657 }658 659 // Check for WP_Error on what should be an image660 if ( is_wp_error( $bp->avatar_admin->image->dir ) ) {661 bp_core_add_message( sprintf( __( 'Upload failed! Error was: %s', 'buddypress' ), $bp->avatar_admin->image->dir->get_error_message() ), 'error' );662 return false;663 }664 665 // If the uploaded image is smaller than the "full" dimensions, throw666 // a warning667 $uploaded_image = @getimagesize( bp_core_avatar_upload_path() . buddypress()->avatar_admin->image->dir );668 $full_width = bp_core_avatar_full_width();669 $full_height = bp_core_avatar_full_height();670 if ( isset( $uploaded_image[0] ) && $uploaded_image[0] < $full_width || $uploaded_image[1] < $full_height ) {671 bp_core_add_message( sprintf( __( 'You have selected an image that is smaller than recommended. For best results, upload a picture larger than %d x %d pixels.', 'buddypress' ), $full_width, $full_height ), 'error' );672 }673 674 // Set the url value for the image675 $bp->avatar_admin->image->url = bp_core_avatar_url() . $bp->avatar_admin->image->dir;676 677 return true;678 }679 680 /**681 * Crop an uploaded avatar.682 *683 * $args has the following parameters:684 * object - What component the avatar is for, e.g. "user"685 * avatar_dir The absolute path to the avatar686 * item_id - Item ID687 * original_file - The absolute path to the original avatar file688 * crop_w - Crop width689 * crop_h - Crop height690 * crop_x - The horizontal starting point of the crop691 * crop_y - The vertical starting point of the crop692 *693 * @param array $args {694 * Array of function parameters.695 * @type string $object Object type of the item whose avatar you're696 * handling. 'user', 'group', 'blog', or custom. Default: 'user'.697 * @type string $avatar_dir Subdirectory where avatar should be stored.698 * Default: 'avatars'.699 * @type bool|int $item_id ID of the item that the avatar belongs to.700 * @type bool|string $original_file Absolute papth to the original avatar701 * file.702 * @type int $crop_w Crop width. Default: the global 'full' avatar width,703 * as retrieved by bp_core_avatar_full_width().704 * @type int $crop_h Crop height. Default: the global 'full' avatar height,705 * as retrieved by bp_core_avatar_full_height().706 * @type int $crop_x The horizontal starting point of the crop. Default: 0.707 * @type int $crop_y The vertical starting point of the crop. Default: 0.708 * }709 * @return bool True on success, false on failure.710 */711 function bp_core_avatar_handle_crop( $args = '' ) {712 713 $r = wp_parse_args( $args, array(714 'object' => 'user',715 'avatar_dir' => 'avatars',716 'item_id' => false,717 'original_file' => false,718 'crop_w' => bp_core_avatar_full_width(),719 'crop_h' => bp_core_avatar_full_height(),720 'crop_x' => 0,721 'crop_y' => 0722 ) );723 724 /***725 * You may want to hook into this filter if you want to override this function.726 * Make sure you return false.727 */728 if ( !apply_filters( 'bp_core_pre_avatar_handle_crop', true, $r ) )729 return true;730 731 extract( $r, EXTR_SKIP );732 733 if ( empty( $original_file ) )734 return false;735 736 $original_file = bp_core_avatar_upload_path() . $original_file;737 738 if ( !file_exists( $original_file ) )739 return false;740 741 if ( empty( $item_id ) ) {742 $avatar_folder_dir = apply_filters( 'bp_core_avatar_folder_dir', dirname( $original_file ), $item_id, $object, $avatar_dir );743 } else {744 $avatar_folder_dir = apply_filters( 'bp_core_avatar_folder_dir', bp_core_avatar_upload_path() . '/' . $avatar_dir . '/' . $item_id, $item_id, $object, $avatar_dir );745 }746 747 if ( !file_exists( $avatar_folder_dir ) )748 return false;749 750 require_once( ABSPATH . '/wp-admin/includes/image.php' );751 require_once( ABSPATH . '/wp-admin/includes/file.php' );752 753 // Delete the existing avatar files for the object754 $existing_avatar = bp_core_fetch_avatar( array(755 'object' => $object,756 'item_id' => $item_id,757 'html' => false,758 ) );759 760 if ( ! empty( $existing_avatar ) ) {761 // Check that the new avatar doesn't have the same name as the762 // old one before deleting763 $upload_dir = wp_upload_dir();764 $existing_avatar_path = str_replace( $upload_dir['baseurl'], '', $existing_avatar );765 $new_avatar_path = str_replace( $upload_dir['basedir'], '', $original_file );766 767 if ( $existing_avatar_path !== $new_avatar_path ) {768 bp_core_delete_existing_avatar( array( 'object' => $object, 'item_id' => $item_id, 'avatar_path' => $avatar_folder_dir ) );769 }770 }771 772 773 774 // Make sure we at least have a width and height for cropping775 if ( empty( $crop_w ) ) {776 $crop_w = bp_core_avatar_full_width();777 }778 779 if ( empty( $crop_h ) ) {780 $crop_h = bp_core_avatar_full_height();781 }782 783 // Get the file extension784 $data = @getimagesize( $original_file );785 $ext = $data['mime'] == 'image/png' ? 'png' : 'jpg';786 787 // Set the full and thumb filenames788 $full_filename = wp_hash( $original_file . time() ) . '-bpfull.' . $ext;789 $thumb_filename = wp_hash( $original_file . time() ) . '-bpthumb.' . $ext;790 791 // Crop the image792 $full_cropped = wp_crop_image( $original_file, (int) $crop_x, (int) $crop_y, (int) $crop_w, (int) $crop_h, bp_core_avatar_full_width(), bp_core_avatar_full_height(), false, $avatar_folder_dir . '/' . $full_filename );793 $thumb_cropped = wp_crop_image( $original_file, (int) $crop_x, (int) $crop_y, (int) $crop_w, (int) $crop_h, bp_core_avatar_thumb_width(), bp_core_avatar_thumb_height(), false, $avatar_folder_dir . '/' . $thumb_filename );794 795 // Check for errors796 if ( empty( $full_cropped ) || empty( $thumb_cropped ) || is_wp_error( $full_cropped ) || is_wp_error( $thumb_cropped ) )797 return false;798 799 // Remove the original800 @unlink( $original_file );801 802 return true;803 }804 805 /**806 388 * Replace default WordPress avatars with BP avatars, if available. 807 389 * 808 390 * Filters 'get_avatar'. … … function bp_core_fetch_avatar_filter( $avatar, $user, $size, $default, $alt = '' 870 452 add_filter( 'get_avatar', 'bp_core_fetch_avatar_filter', 10, 5 ); 871 453 872 454 /** 873 * Is the current avatar upload error-free?874 *875 * @param array $file The $_FILES array.876 * @return bool True if no errors are found. False if there are errors.877 */878 function bp_core_check_avatar_upload( $file ) {879 if ( isset( $file['error'] ) && $file['error'] )880 return false;881 882 return true;883 }884 885 /**886 * Is the file size of the current avatar upload permitted?887 *888 * @param array $file The $_FILES array.889 * @return bool True if the avatar is under the size limit, otherwise false.890 */891 function bp_core_check_avatar_size( $file ) {892 if ( $file['file']['size'] > bp_core_avatar_original_max_filesize() )893 return false;894 895 return true;896 }897 898 /**899 * Does the current avatar upload have an allowed file type?900 *901 * Permitted file types are JPG, GIF and PNG.902 *903 * @param array $file The $_FILES array.904 * @return bool True if the file extension is permitted, otherwise false.905 */906 function bp_core_check_avatar_type($file) {907 if ( ( !empty( $file['file']['type'] ) && !preg_match('/(jpe?g|gif|png)$/i', $file['file']['type'] ) ) || !preg_match( '/(jpe?g|gif|png)$/i', $file['file']['name'] ) )908 return false;909 910 return true;911 }912 913 /**914 * Fetch data from the BP root blog's upload directory.915 *916 * Handy for multisite instances because all uploads are made on the BP root917 * blog and we need to query the BP root blog for the upload directory data.918 *919 * This function ensures that we only need to use {@link switch_to_blog()}920 * once to get what we need.921 *922 * @since BuddyPress (1.8.0)923 *924 * @uses wp_upload_dir()925 *926 * @param string $type The variable we want to return from the $bp->avatars927 * object. Only 'upload_path' and 'url' are supported. Default: 'upload_path'.928 * @return string The avatar upload directory path.929 */930 function bp_core_get_upload_dir( $type = 'upload_path' ) {931 $bp = buddypress();932 933 switch ( $type ) {934 case 'upload_path' :935 $constant = 'BP_AVATAR_UPLOAD_PATH';936 $key = 'basedir';937 938 break;939 940 case 'url' :941 $constant = 'BP_AVATAR_URL';942 $key = 'baseurl';943 944 break;945 946 default :947 return false;948 949 break;950 }951 952 // See if the value has already been calculated and stashed in the $bp global953 if ( isset( $bp->avatar->$type ) ) {954 $retval = $bp->avatar->$type;955 } else {956 // If this value has been set in a constant, just use that957 if ( defined( $constant ) ) {958 $retval = constant( $constant );959 } else {960 961 // Use cached upload dir data if available962 if ( ! empty( $bp->avatar->upload_dir ) ) {963 $upload_dir = $bp->avatar->upload_dir;964 965 // No cache, so query for it966 } else {967 // We need to switch to the root blog on multisite installs968 if ( is_multisite() ) {969 switch_to_blog( bp_get_root_blog_id() );970 }971 972 // Get upload directory information from current site973 $upload_dir = wp_upload_dir();974 975 // Will bail if not switched976 restore_current_blog();977 978 // Stash upload directory data for later use979 $bp->avatar->upload_dir = $upload_dir;980 }981 982 // Directory does not exist and cannot be created983 if ( ! empty( $upload_dir['error'] ) ) {984 $retval = '';985 986 } else {987 $retval = $upload_dir[$key];988 989 // If $key is 'baseurl', check to see if we're on SSL990 // Workaround for WP13941, WP15928, WP19037.991 if ( $key == 'baseurl' && is_ssl() ) {992 $retval = str_replace( 'http://', 'https://', $retval );993 }994 }995 996 }997 998 // Stash in $bp for later use999 $bp->avatar->$type = $retval;1000 }1001 1002 return $retval;1003 }1004 1005 /**1006 * Get the absolute upload path for the WP installation.1007 *1008 * @uses wp_upload_dir To get upload directory info1009 *1010 * @return string Absolute path to WP upload directory.1011 */1012 function bp_core_avatar_upload_path() {1013 return apply_filters( 'bp_core_avatar_upload_path', bp_core_get_upload_dir() );1014 }1015 1016 /**1017 * Get the raw base URL for root site upload location.1018 *1019 * @uses wp_upload_dir To get upload directory info.1020 *1021 * @return string Full URL to current upload location.1022 */1023 function bp_core_avatar_url() {1024 return apply_filters( 'bp_core_avatar_url', bp_core_get_upload_dir( 'url' ) );1025 }1026 1027 /**1028 455 * Check if a given user ID has an uploaded avatar. 1029 456 * 1030 457 * @since BuddyPress (1.0.0) … … function bp_core_avatar_full_height() { 1107 534 } 1108 535 1109 536 /** 1110 * Get the max width for original avatar uploads.1111 *1112 * @since BuddyPress (1.5.0)1113 *1114 * @return int The max width for original avatar uploads.1115 */1116 function bp_core_avatar_original_max_width() {1117 return apply_filters( 'bp_core_avatar_original_max_width', (int) buddypress()->avatar->original_max_width );1118 }1119 1120 /**1121 * Get the max filesize for original avatar uploads.1122 *1123 * @since BuddyPress (1.5.0)1124 *1125 * @return int The max filesize for original avatar uploads.1126 */1127 function bp_core_avatar_original_max_filesize() {1128 return apply_filters( 'bp_core_avatar_original_max_filesize', (int) buddypress()->avatar->original_max_filesize );1129 }1130 1131 /**1132 537 * Get the URL of the 'full' default avatar. 1133 538 * 1134 539 * @since BuddyPress (1.5.0) -
src/bp-core/bp-core-component.php
diff --git src/bp-core/bp-core-component.php src/bp-core/bp-core-component.php index 539359f..9bd3b82 100644
class BP_Component { 125 125 */ 126 126 public $global_tables = array(); 127 127 128 public $can_attachments = false; 129 128 130 /** Methods ***************************************************************/ 129 131 130 132 /** … … class BP_Component { 220 222 'search_string' => '', 221 223 'global_tables' => '', 222 224 'meta_tables' => '', 225 'can_attachments' => false, 223 226 ) ); 224 227 225 228 // Slug used for permalink URI chunk after root … … class BP_Component { 250 253 $this->register_meta_tables( $r['meta_tables'] ); 251 254 } 252 255 256 // Use Attachments 257 if ( ! empty( $r['can_attachments'] ) ) { 258 $this->can_attachments = apply_filters( 'bp_' . $this->id . '_can_attachments', $r['can_attachments'] ); 259 } 260 253 261 /** BuddyPress ********************************************************/ 254 262 255 263 // Register this component in the loaded components array -
src/bp-core/bp-core-cssjs.php
diff --git src/bp-core/bp-core-cssjs.php src/bp-core/bp-core-cssjs.php index ce59ad2..181e60f 100644
if ( !defined( 'ABSPATH' ) ) exit; 17 17 function bp_core_register_common_scripts() { 18 18 $min = defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ? '' : '.min'; 19 19 $url = buddypress()->plugin_url . 'bp-core/js/'; 20 20 21 21 $scripts = apply_filters( 'bp_core_register_common_scripts', array( 22 22 23 23 // Legacy … … add_action( 'bp_enqueue_scripts', 'bp_core_confirmation_js' ); 86 86 add_action( 'admin_enqueue_scripts', 'bp_core_confirmation_js' ); 87 87 88 88 /** 89 * Enqueues jCrop library and hooks BP's custom cropper JS.90 */91 function bp_core_add_jquery_cropper() {92 wp_enqueue_style( 'jcrop' );93 wp_enqueue_script( 'jcrop', array( 'jquery' ) );94 add_action( 'wp_head', 'bp_core_add_cropper_inline_js' );95 add_action( 'wp_head', 'bp_core_add_cropper_inline_css' );96 }97 98 /**99 * Output the inline JS needed for the cropper to work on a per-page basis.100 */101 function bp_core_add_cropper_inline_js() {102 103 // Bail if no image was uploaded104 $image = apply_filters( 'bp_inline_cropper_image', getimagesize( bp_core_avatar_upload_path() . buddypress()->avatar_admin->image->dir ) );105 if ( empty( $image ) ) {106 return;107 }108 109 // Get avatar full width and height110 $full_height = bp_core_avatar_full_height();111 $full_width = bp_core_avatar_full_width();112 113 // Calculate Aspect Ratio114 if ( !empty( $full_height ) && ( $full_width != $full_height ) ) {115 $aspect_ratio = $full_width / $full_height;116 } else {117 $aspect_ratio = 1;118 }119 120 // Default cropper coordinates121 122 // Smaller than full-width: cropper defaults to entire image123 if ( $image[0] < $full_width ) {124 $crop_left = 0;125 $crop_right = $image[0];126 127 // Less than 2x full-width: cropper defaults to full-width128 } else if ( $image[0] < ( $full_width * 2 ) ) {129 $padding_w = round( ( $image[0] - $full_width ) / 2 );130 $crop_left = $padding_w;131 $crop_right = $image[0] - $padding_w;132 133 // Larger than 2x full-width: cropper defaults to 1/2 image width134 } else {135 $crop_left = round( $image[0] / 4 );136 $crop_right = $image[0] - $crop_left;137 }138 139 // Smaller than full-height: cropper defaults to entire image140 if ( $image[1] < $full_height ) {141 $crop_top = 0;142 $crop_bottom = $image[1];143 144 // Less than double full-height: cropper defaults to full-height145 } else if ( $image[1] < ( $full_height * 2 ) ) {146 $padding_h = round( ( $image[1] - $full_height ) / 2 );147 $crop_top = $padding_h;148 $crop_bottom = $image[1] - $padding_h;149 150 // Larger than 2x full-height: cropper defaults to 1/2 image height151 } else {152 $crop_top = round( $image[1] / 4 );153 $crop_bottom = $image[1] - $crop_top;154 }155 156 ?>157 158 <script type="text/javascript">159 jQuery(window).load( function(){160 jQuery('#avatar-to-crop').Jcrop({161 onChange: showPreview,162 onSelect: updateCoords,163 aspectRatio: <?php echo (int) $aspect_ratio; ?>,164 setSelect: [ <?php echo (int) $crop_left; ?>, <?php echo (int) $crop_top; ?>, <?php echo (int) $crop_right; ?>, <?php echo (int) $crop_bottom; ?> ]165 });166 updateCoords({x: <?php echo (int) $crop_left; ?>, y: <?php echo (int) $crop_top; ?>, w: <?php echo (int) $crop_right; ?>, h: <?php echo (int) $crop_bottom; ?>});167 });168 169 function updateCoords(c) {170 jQuery('#x').val(c.x);171 jQuery('#y').val(c.y);172 jQuery('#w').val(c.w);173 jQuery('#h').val(c.h);174 }175 176 function showPreview(coords) {177 if ( parseInt(coords.w) > 0 ) {178 var fw = <?php echo (int) $full_width; ?>;179 var fh = <?php echo (int) $full_height; ?>;180 var rx = fw / coords.w;181 var ry = fh / coords.h;182 183 jQuery( '#avatar-crop-preview' ).css({184 width: Math.round(rx * <?php echo (int) $image[0]; ?>) + 'px',185 height: Math.round(ry * <?php echo (int) $image[1]; ?>) + 'px',186 marginLeft: '-' + Math.round(rx * coords.x) + 'px',187 marginTop: '-' + Math.round(ry * coords.y) + 'px'188 });189 }190 }191 </script>192 193 <?php194 }195 196 /**197 * Output the inline CSS for the BP image cropper.198 *199 * @package BuddyPress Core200 */201 function bp_core_add_cropper_inline_css() {202 ?>203 204 <style type="text/css">205 .jcrop-holder { float: left; margin: 0 20px 20px 0; text-align: left; }206 #avatar-crop-pane { width: <?php echo bp_core_avatar_full_width() ?>px; height: <?php echo bp_core_avatar_full_height() ?>px; overflow: hidden; }207 #avatar-crop-submit { margin: 20px 0; }208 .jcrop-holder img,209 #avatar-crop-pane img,210 #avatar-upload-form img,211 #create-group-form img,212 #group-settings-form img { border: none !important; max-width: none !important; }213 </style>214 215 <?php216 }217 218 /**219 89 * Define the 'ajaxurl' JS variable, used by themes as an AJAX endpoint. 220 90 * 221 91 * @since BuddyPress (1.1.0) -
src/bp-core/bp-core-loader.php
diff --git src/bp-core/bp-core-loader.php src/bp-core/bp-core-loader.php index 6b0d556..ccc7857 100644
class BP_Core extends BP_Component { 54 54 /** Components ********************************************************/ 55 55 56 56 // Set the included and optional components. 57 $bp->optional_components = apply_filters( 'bp_optional_components', array( 'activity', ' blogs', 'forums', 'friends', 'groups', 'messages', 'notifications', 'settings', 'xprofile' ) );57 $bp->optional_components = apply_filters( 'bp_optional_components', array( 'activity', 'attachments', 'blogs', 'forums', 'friends', 'groups', 'messages', 'notifications', 'settings', 'xprofile' ) ); 58 58 59 59 // Set the required components 60 60 $bp->required_components = apply_filters( 'bp_required_components', array( 'members' ) ); -
src/bp-core/bp-core-update.php
diff --git src/bp-core/bp-core-update.php src/bp-core/bp-core-update.php index 6b27154..da05267 100644
function bp_version_updater() { 193 193 'settings' => 1, 194 194 'xprofile' => 1, 195 195 'notifications' => 1, 196 'attachments' => 1, 196 197 ) ); 197 198 198 199 require_once( buddypress()->plugin_dir . '/bp-core/admin/bp-core-schema.php' ); … … function bp_version_updater() { 241 242 if ( $raw_db_version < 8311 ) { 242 243 bp_update_to_2_0_1(); 243 244 } 245 246 // 2.2 247 if ( $raw_db_version < 9131 ) { 248 bp_update_to_2_2(); 249 } 244 250 } 245 251 246 252 /** All done! *************************************************************/ … … function bp_update_to_1_6() { 299 305 * component to the active components option to retain existing functionality. 300 306 * 301 307 * @since BuddyPress (1.9.0) 308 * 309 * @uses bp_update_active_components() to activate the notifications component 302 310 */ 303 311 function bp_update_to_1_9() { 304 305 // Setup hardcoded keys 306 $active_components_key = 'bp-active-components'; 307 $notifications_component_id = 'notifications'; 308 309 // Get the active components 310 $active_components = bp_get_option( $active_components_key ); 311 312 // Add notifications 313 if ( ! in_array( $notifications_component_id, $active_components ) ) { 314 $active_components[ $notifications_component_id ] = 1; 315 } 316 317 // Update the active components option 318 bp_update_option( $active_components_key, $active_components ); 312 bp_update_active_components( 'notifications' ); 319 313 } 320 314 321 315 /** … … function bp_update_to_2_0_1() { 390 384 } 391 385 392 386 /** 387 * 2.2 upgrade routine 388 * 389 * Checks if avatar uploads are not disabled and eventually activate Attachments 390 * component 391 * 392 * @since BuddyPress (2.2.0) 393 * 394 * @uses bp_update_active_components() to activate the attachments component 395 * @return void 396 */ 397 function bp_update_to_2_2() { 398 /** 399 * Only activate Attachments if avatar uploads 400 * are not disabled 401 */ 402 if ( bp_disable_avatar_uploads() ) { 403 return; 404 } 405 406 bp_update_active_components( 'attachments' ); 407 } 408 409 /** 410 * Update the active components 411 * 412 * When a component has been created by moving bp-core features, this 413 * function make sure it will be activated if needed. 414 * 415 * @since BuddyPress (2.2.0) 416 * 417 * @return void 418 */ 419 function bp_update_active_components( $new_component_id = '' ) { 420 if ( empty( $new_component_id ) ) { 421 return; 422 } 423 424 // Setup hardcoded keys 425 $active_components_key = 'bp-active-components'; 426 427 // Get the active components 428 $active_components = bp_get_option( $active_components_key ); 429 430 // Add notifications 431 if ( ! in_array( $new_component_id, $active_components ) ) { 432 $active_components[ $new_component_id ] = 1; 433 } 434 435 // Update the active components option 436 bp_update_option( $active_components_key, $active_components ); 437 } 438 439 /** 393 440 * Redirect user to BP's What's New page on first page load after activation. 394 441 * 395 442 * @since BuddyPress (1.7.0) -
src/bp-core/deprecated/2.2.php
diff --git src/bp-core/deprecated/2.2.php src/bp-core/deprecated/2.2.php index e69de29..e4d24f7 100644
1 <?php 2 /** 3 * Deprecated functions 4 * 5 * @package BuddyPress 6 * @subpackage Core 7 * @deprecated 2.2.0 8 */ 9 10 // Exit if accessed directly 11 defined( 'ABSPATH' ) or exit; 12 13 /** Core Avatars **************************************************************/ 14 15 /** 16 * Fetch data from the BP root blog's upload directory. 17 * 18 * Handy for multisite instances because all uploads are made on the BP root 19 * blog and we need to query the BP root blog for the upload directory data. 20 * 21 * This function ensures that we only need to use {@link switch_to_blog()} 22 * once to get what we need. 23 * 24 * @since BuddyPress (1.8.0) 25 * @deprecated BuddyPress (2.2.0) 26 * 27 * @uses wp_upload_dir() 28 * 29 * @param string $type The variable we want to return from the $bp->avatars 30 * object. Only 'upload_path' and 'url' are supported. Default: 'upload_path'. 31 * @return string The avatar upload directory path. 32 */ 33 function bp_core_get_upload_dir( $type = 'upload_path' ) { 34 if ( bp_is_active( 'attachments' ) ) { 35 _deprecated_function( __FUNCTION__, '2.2.0', 'bp_attachments_get_upload_dir()' ); 36 return bp_attachments_get_upload_dir( $type ); 37 } else { 38 _doing_it_wrong( 39 __FUNCTION__, 40 __( 'bp_core_get_upload_dir() has been replaced by bp_attachments_get_upload_dir() which requires the Attachments component to be active.', 'buddypress' ), 41 '2.2.0' 42 ); 43 } 44 45 } 46 47 /** 48 * Get the absolute upload path for the WP installation. 49 * 50 * @deprecated BuddyPress (2.2.0) 51 * 52 * @uses wp_upload_dir To get upload directory info 53 * 54 * @return string Absolute path to WP upload directory. 55 */ 56 function bp_core_avatar_upload_path() { 57 if ( bp_is_active( 'attachments' ) ) { 58 _deprecated_function( __FUNCTION__, '2.2.0', 'bp_attachments_get_upload_dir()' ); 59 return bp_attachments_get_upload_dir(); 60 } else { 61 _doing_it_wrong( 62 __FUNCTION__, 63 __( 'bp_core_avatar_upload_path() has been replaced by bp_attachments_get_upload_dir() which requires the Attachments component to be active.', 'buddypress' ), 64 '2.2.0' 65 ); 66 } 67 } 68 69 /** 70 * Get the raw base URL for root site upload location. 71 * 72 * @deprecated BuddyPress (2.2.0) 73 * 74 * @uses wp_upload_dir To get upload directory info. 75 * 76 * @return string Full URL to current upload location. 77 */ 78 function bp_core_avatar_url() { 79 if ( bp_is_active( 'attachments' ) ) { 80 _deprecated_function( __FUNCTION__, '2.2.0', "bp_attachments_get_upload_dir( 'url' )" ); 81 return bp_attachments_get_upload_dir( 'url' ); 82 } else { 83 _doing_it_wrong( 84 __FUNCTION__, 85 __( "bp_core_avatar_url() has been replaced by bp_attachments_get_upload_dir( 'url' ) which requires the Attachments component to be active.", 'buddypress' ), 86 '2.2.0' 87 ); 88 } 89 } 90 91 /** 92 * Delete an existing avatar. 93 * 94 * @deprecated BuddyPress (2.2.0) 95 * 96 * @param array $args { 97 * Array of function parameters. 98 * @type bool|int $item_id ID of the item whose avatar you're deleting. 99 * Defaults to the current item of type $object. 100 * @type string $object Object type of the item whose avatar you're 101 * deleting. 'user', 'group', 'blog', or custom. Default: 'user'. 102 * @type bool|string $avatar_dir Subdirectory where avatar is located. 103 * Default: false, which falls back on the default location 104 * corresponding to the $object. 105 * } 106 * @return bool True on success, false on failure. 107 */ 108 function bp_core_delete_existing_avatar( $args = '' ) { 109 if ( bp_is_active( 'attachments' ) ) { 110 _deprecated_function( __FUNCTION__, '2.2.0', 'bp_attachments_delete_existing_avatar()' ); 111 return bp_attachments_delete_existing_avatar( $args ); 112 } else { 113 _doing_it_wrong( 114 __FUNCTION__, 115 __( 'bp_core_delete_existing_avatar() has been replaced by bp_attachments_delete_existing_avatar() which requires the Attachments component to be active.', 'buddypress' ), 116 '2.2.0' 117 ); 118 } 119 } 120 121 /** 122 * Handle avatar uploading. 123 * 124 * The functions starts off by checking that the file has been uploaded 125 * properly using bp_core_check_avatar_upload(). It then checks that the file 126 * size is within limits, and that it has an accepted file extension (jpg, gif, 127 * png). If everything checks out, crop the image and move it to its real 128 * location. 129 * 130 * @deprecated BuddyPress (2.2.0) 131 * 132 * @see bp_core_check_avatar_upload() 133 * @see bp_core_check_avatar_type() 134 * 135 * @param array $file The appropriate entry the from $_FILES superglobal. 136 * @param string $upload_dir_filter A filter to be applied to 'upload_dir'. 137 * @return bool True on success, false on failure. 138 */ 139 function bp_core_avatar_handle_upload( $file, $upload_dir_filter ) { 140 if ( bp_is_active( 'attachments' ) ) { 141 _deprecated_function( __FUNCTION__, '2.2.0', 'bp_attachments_avatar_handle_upload()' ); 142 return bp_attachments_avatar_handle_upload( $file, $upload_dir_filter ); 143 } else { 144 _doing_it_wrong( 145 __FUNCTION__, 146 __( 'bp_core_avatar_handle_upload() has been replaced by bp_attachments_avatar_handle_upload() which requires the Attachments component to be active.', 'buddypress' ), 147 '2.2.0' 148 ); 149 } 150 } 151 152 /** 153 * Crop an uploaded avatar. 154 * 155 * $args has the following parameters: 156 * object - What component the avatar is for, e.g. "user" 157 * avatar_dir The absolute path to the avatar 158 * item_id - Item ID 159 * original_file - The absolute path to the original avatar file 160 * crop_w - Crop width 161 * crop_h - Crop height 162 * crop_x - The horizontal starting point of the crop 163 * crop_y - The vertical starting point of the crop 164 * 165 * @deprecated BuddyPress (2.2.0) 166 * 167 * @param array $args { 168 * Array of function parameters. 169 * @type string $object Object type of the item whose avatar you're 170 * handling. 'user', 'group', 'blog', or custom. Default: 'user'. 171 * @type string $avatar_dir Subdirectory where avatar should be stored. 172 * Default: 'avatars'. 173 * @type bool|int $item_id ID of the item that the avatar belongs to. 174 * @type bool|string $original_file Absolute papth to the original avatar 175 * file. 176 * @type int $crop_w Crop width. Default: the global 'full' avatar width, 177 * as retrieved by bp_core_avatar_full_width(). 178 * @type int $crop_h Crop height. Default: the global 'full' avatar height, 179 * as retrieved by bp_core_avatar_full_height(). 180 * @type int $crop_x The horizontal starting point of the crop. Default: 0. 181 * @type int $crop_y The vertical starting point of the crop. Default: 0. 182 * } 183 * @return bool True on success, false on failure. 184 */ 185 function bp_core_avatar_handle_crop( $args = '' ) { 186 if ( bp_is_active( 'attachments' ) ) { 187 _deprecated_function( __FUNCTION__, '2.2.0', 'bp_attachments_avatar_handle_crop()' ); 188 return bp_attachments_avatar_handle_crop( $args ); 189 } else { 190 _doing_it_wrong( 191 __FUNCTION__, 192 __( 'bp_core_avatar_handle_crop() has been replaced by bp_attachments_avatar_handle_crop() which requires the Attachments component to be active.', 'buddypress' ), 193 '2.2.0' 194 ); 195 } 196 } 197 198 /** 199 * Is the current avatar upload error-free? 200 * 201 * @deprecated BuddyPress (2.2.0) 202 * 203 * @param array $file The $_FILES array. 204 * @return bool True if no errors are found. False if there are errors. 205 */ 206 function bp_core_check_avatar_upload( $file ) { 207 if ( bp_is_active( 'attachments' ) ) { 208 _deprecated_function( __FUNCTION__, '2.2.0', 'bp_attachments_check_avatar_upload()' ); 209 return bp_attachments_check_avatar_upload( $file ); 210 } else { 211 _doing_it_wrong( 212 __FUNCTION__, 213 __( 'bp_core_check_avatar_upload() has been replaced by bp_attachments_check_avatar_upload() which requires the Attachments component to be active.', 'buddypress' ), 214 '2.2.0' 215 ); 216 } 217 } 218 219 /** 220 * Is the file size of the current avatar upload permitted? 221 * 222 * @deprecated BuddyPress (2.2.0) 223 * 224 * @param array $file The $_FILES array. 225 * @return bool True if the avatar is under the size limit, otherwise false. 226 */ 227 function bp_core_check_avatar_size( $file ) { 228 if ( bp_is_active( 'attachments' ) ) { 229 _deprecated_function( __FUNCTION__, '2.2.0', 'bp_attachments_check_avatar_size()' ); 230 return bp_attachments_check_avatar_size( $file ); 231 } else { 232 _doing_it_wrong( 233 __FUNCTION__, 234 __( 'bp_core_check_avatar_size() has been replaced by bp_attachments_check_avatar_size() which requires the Attachments component to be active.', 'buddypress' ), 235 '2.2.0' 236 ); 237 } 238 } 239 240 /** 241 * Does the current avatar upload have an allowed file type? 242 * 243 * Permitted file types are JPG, GIF and PNG. 244 * 245 * @deprecated BuddyPress (2.2.0) 246 * 247 * @param array $file The $_FILES array. 248 * @return bool True if the file extension is permitted, otherwise false. 249 */ 250 function bp_core_check_avatar_type( $file ) { 251 if ( bp_is_active( 'attachments' ) ) { 252 _deprecated_function( __FUNCTION__, '2.2.0', 'bp_attachments_check_avatar_type()' ); 253 return bp_attachments_check_avatar_type( $file ); 254 } else { 255 _doing_it_wrong( 256 __FUNCTION__, 257 __( 'bp_core_check_avatar_type() has been replaced by bp_attachments_check_avatar_type() which requires the Attachments component to be active.', 'buddypress' ), 258 '2.2.0' 259 ); 260 } 261 } 262 263 /** 264 * Get the max width for original avatar uploads. 265 * 266 * @since BuddyPress (1.5.0) 267 * @deprecated BuddyPress (2.2.0) 268 * 269 * @return int The max width for original avatar uploads. 270 */ 271 function bp_core_avatar_original_max_width() { 272 if ( bp_is_active( 'attachments' ) ) { 273 _deprecated_function( __FUNCTION__, '2.2.0', 'bp_attachments_avatar_original_max_width()' ); 274 return bp_attachments_avatar_original_max_width(); 275 } else { 276 _doing_it_wrong( 277 __FUNCTION__, 278 __( 'bp_core_avatar_original_max_width() has been replaced by bp_attachments_avatar_original_max_width() which requires the Attachments component to be active.', 'buddypress' ), 279 '2.2.0' 280 ); 281 } 282 } 283 284 /** 285 * Get the max filesize for original avatar uploads. 286 * 287 * @since BuddyPress (1.5.0) 288 * @deprecated BuddyPress (2.2.0) 289 * 290 * @return int The max filesize for original avatar uploads. 291 */ 292 function bp_core_avatar_original_max_filesize() { 293 if ( bp_is_active( 'attachments' ) ) { 294 _deprecated_function( __FUNCTION__, '2.2.0', 'bp_attachments_avatar_original_max_filesize()' ); 295 return bp_attachments_avatar_original_max_filesize(); 296 } else { 297 _doing_it_wrong( 298 __FUNCTION__, 299 __( 'bp_core_avatar_original_max_filesize() has been replaced by bp_attachments_avatar_original_max_filesize() which requires the Attachments component to be active.', 'buddypress' ), 300 '2.2.0' 301 ); 302 } 303 } 304 305 /** 306 * Enqueues jCrop library and hooks BP's custom cropper JS. 307 * 308 * @deprecated BuddyPress (2.2.0) 309 */ 310 function bp_core_add_jquery_cropper() { 311 if ( bp_is_active( 'attachments' ) ) { 312 _deprecated_function( __FUNCTION__, '2.2.0', 'bp_attachments_add_jquery_cropper()' ); 313 return bp_attachments_add_jquery_cropper(); 314 } else { 315 _doing_it_wrong( 316 __FUNCTION__, 317 __( 'bp_core_add_jquery_cropper() has been replaced by bp_attachments_add_jquery_cropper() which requires the Attachments component to be active.', 'buddypress' ), 318 '2.2.0' 319 ); 320 } 321 } 322 323 /** 324 * Output the inline JS needed for the cropper to work on a per-page basis. 325 * 326 * @deprecated BuddyPress (2.2.0) 327 */ 328 function bp_core_add_cropper_inline_js() { 329 if ( bp_is_active( 'attachments' ) ) { 330 _deprecated_function( __FUNCTION__, '2.2.0', 'bp_attachments_add_cropper_inline_js()' ); 331 return bp_attachments_add_cropper_inline_js(); 332 } else { 333 _doing_it_wrong( 334 __FUNCTION__, 335 __( 'bp_core_add_cropper_inline_js() has been replaced by bp_attachments_add_cropper_inline_js() which requires the Attachments component to be active.', 'buddypress' ), 336 '2.2.0' 337 ); 338 } 339 } 340 341 /** 342 * Output the inline CSS for the BP image cropper. 343 * 344 * @deprecated BuddyPress (2.2.0) 345 * 346 * @package BuddyPress Core 347 */ 348 function bp_core_add_cropper_inline_css() { 349 if ( bp_is_active( 'attachments' ) ) { 350 _deprecated_function( __FUNCTION__, '2.2.0', 'bp_attachments_add_cropper_inline_css()' ); 351 return bp_attachments_add_cropper_inline_css(); 352 } else { 353 _doing_it_wrong( 354 __FUNCTION__, 355 __( 'bp_core_add_cropper_inline_css() has been replaced by bp_attachments_add_cropper_inline_css() which requires the Attachments component to be active.', 'buddypress' ), 356 '2.2.0' 357 ); 358 } 359 } 360 361 /** xProfile Avatars **********************************************************/ 362 363 /** 364 * Setup the avatar upload directory for a user. 365 * 366 * @since BuddyPress (1.0.0) 367 * @deprecated BuddyPress (2.2.0) 368 * 369 * @package BuddyPress Core 370 * 371 * @param string $directory The root directory name. Optional. 372 * @param int $user_id The user ID. Optional. 373 * 374 * @return array() Array containing the path, URL, and other helpful settings. 375 */ 376 function xprofile_avatar_upload_dir( $directory = 'avatars', $user_id = 0 ) { 377 if ( bp_is_active( 'attachments' ) ) { 378 _deprecated_function( __FUNCTION__, '2.2.0', 'bp_attachments_xprofile_avatar_upload_dir()' ); 379 return bp_attachments_user_avatar_upload_dir( $directory, $user_id ); 380 } else { 381 _doing_it_wrong( 382 __FUNCTION__, 383 __( 'xprofile_avatar_upload_dir() has been replaced by bp_attachments_xprofile_avatar_upload_dir() which requires the Attachments component to be active.', 'buddypress' ), 384 '2.2.0' 385 ); 386 } 387 } 388 389 /** 390 * Handles the uploading and cropping of a user avatar. Displays the change avatar page. 391 * 392 * @deprecated BuddyPress (2.2.0) 393 * 394 * @package BuddyPress XProfile 395 * @uses bp_is_my_profile() Checks to make sure the current user being viewed equals the logged in user 396 * @uses bp_core_load_template() Looks for and loads a template file within the current member theme (folder/filename) 397 */ 398 function xprofile_screen_change_avatar() { 399 $screen_function = 'bp_xprofile_screen_change_gravatar'; 400 401 if ( bp_is_active( 'attachments' ) ) { 402 $screen_function = 'bp_attachments_screen_change_avatar'; 403 } 404 _deprecated_function( __FUNCTION__, '2.2.0', sprintf( '%s()', $screen_function ) ); 405 return call_user_func( $screen_function ); 406 } 407 408 /** 409 * This function runs when an action is set for a screen: 410 * example.com/members/andy/profile/change-avatar/ [delete-avatar] 411 * 412 * The function will delete the active avatar for a user. 413 * 414 * @deprecated BuddyPress (2.2.0) 415 * 416 * @package BuddyPress Xprofile 417 * @uses bp_core_delete_avatar() Deletes the active avatar for the logged in user. 418 * @uses add_action() Runs a specific function for an action when it fires. 419 */ 420 function xprofile_action_delete_avatar() { 421 if ( bp_is_active( 'attachments' ) ) { 422 _deprecated_function( __FUNCTION__, '2.2.0', 'bp_attachments_action_xprofile_delete_avatar()' ); 423 return bp_attachments_action_xprofile_delete_avatar(); 424 } else { 425 _doing_it_wrong( 426 __FUNCTION__, 427 __( 'xprofile_action_delete_avatar() has been replaced by bp_attachments_action_xprofile_delete_avatar() which requires the Attachments component to be active.', 'buddypress' ), 428 '2.2.0' 429 ); 430 } 431 } 432 433 /** Group Avatars *************************************************************/ 434 435 /** 436 * Handle the display of a group's Change Avatar page. 437 * 438 * @deprecated BuddyPress (2.2.0) 439 */ 440 function groups_screen_group_admin_avatar() { 441 if ( bp_is_active( 'attachments' ) ) { 442 _deprecated_function( __FUNCTION__, '2.2.0', 'bp_attachments_screen_group_admin_avatar()' ); 443 return bp_attachments_screen_group_admin_avatar(); 444 } else { 445 _doing_it_wrong( 446 __FUNCTION__, 447 __( 'groups_screen_group_admin_avatar() has been replaced by bp_attachments_screen_group_admin_avatar() which requires the Attachments component to be active.', 'buddypress' ), 448 '2.2.0' 449 ); 450 } 451 } 452 453 /** 454 * Generate the avatar upload directory path for a given group. 455 * 456 * @deprecated BuddyPress (2.2.0) 457 * 458 * @param int $group_id Optional. ID of the group. Default: ID of the 459 * current group. 460 * @return string 461 */ 462 function groups_avatar_upload_dir( $group_id = 0 ) { 463 if ( bp_is_active( 'attachments' ) ) { 464 _deprecated_function( __FUNCTION__, '2.2.0', 'bp_attachments_groups_avatar_upload_dir()' ); 465 return bp_attachments_group_avatar_upload_dir( $group_id ); 466 } else { 467 _doing_it_wrong( 468 __FUNCTION__, 469 __( 'groups_avatar_upload_dir() has been replaced by bp_attachments_groups_avatar_upload_dir() which requires the Attachments component to be active.', 'buddypress' ), 470 '2.2.0' 471 ); 472 } 473 } 474 475 /** 476 * Get the avatar storage directory for use during registration. 477 * 478 * @deprecated BuddyPress (2.2.0) 479 * 480 * @return string|bool Directory path on success, false on failure. 481 */ 482 function bp_core_signup_avatar_upload_dir() { 483 if ( bp_is_active( 'attachments' ) ) { 484 _deprecated_function( __FUNCTION__, '2.2.0', 'bp_attachments_signup_avatar_upload_dir()' ); 485 return bp_attachments_signup_avatar_upload_dir(); 486 } else { 487 _doing_it_wrong( 488 __FUNCTION__, 489 __( 'bp_core_signup_avatar_upload_dir() has been replaced by bp_attachments_signup_avatar_upload_dir() which requires the Attachments component to be active.', 'buddypress' ), 490 '2.2.0' 491 ); 492 } 493 } -
src/bp-groups/bp-groups-actions.php
diff --git src/bp-groups/bp-groups-actions.php src/bp-groups/bp-groups-actions.php index 163e407..07bfc3d 100644
function groups_action_create_group() { 283 283 bp_core_redirect( bp_get_root_domain() . '/' . bp_get_groups_root_slug() . '/create/step/group-invites/' ); 284 284 } 285 285 286 // Group avatar is handled separately 287 if ( 'group-avatar' == bp_get_groups_current_create_step() && isset( $_POST['upload'] ) ) { 288 if ( ! isset( $bp->avatar_admin ) ) { 289 $bp->avatar_admin = new stdClass(); 290 } 291 292 if ( !empty( $_FILES ) && isset( $_POST['upload'] ) ) { 293 // Normally we would check a nonce here, but the group save nonce is used instead 294 295 // Pass the file to the avatar upload handler 296 if ( bp_core_avatar_handle_upload( $_FILES, 'groups_avatar_upload_dir' ) ) { 297 $bp->avatar_admin->step = 'crop-image'; 298 299 // Make sure we include the jQuery jCrop file for image cropping 300 add_action( 'wp_print_scripts', 'bp_core_add_jquery_cropper' ); 301 } 302 } 303 304 // If the image cropping is done, crop the image and save a full/thumb version 305 if ( isset( $_POST['avatar-crop-submit'] ) && isset( $_POST['upload'] ) ) { 306 // Normally we would check a nonce here, but the group save nonce is used instead 286 /** 287 * Group avatar is handled in Attachments component 288 * Please do not use this action, for internal use only 289 */ 290 do_action( 'bp_groups_avatar_create_step' ); 307 291 308 if ( !bp_core_avatar_handle_crop( array( 'object' => 'group', 'avatar_dir' => 'group-avatars', 'item_id' => $bp->groups->current_group->id, 'original_file' => $_POST['image_src'], 'crop_x' => $_POST['x'], 'crop_y' => $_POST['y'], 'crop_w' => $_POST['w'], 'crop_h' => $_POST['h'] ) ) )309 bp_core_add_message( __( 'There was an error saving the group profile photo, please try uploading again.', 'buddypress' ), 'error' );310 else311 bp_core_add_message( __( 'The group profile photo was uploaded successfully!', 'buddypress' ) );312 }313 }314 292 315 293 bp_core_load_template( apply_filters( 'groups_template_create_group', 'groups/create' ) ); 316 294 } -
src/bp-groups/bp-groups-functions.php
diff --git src/bp-groups/bp-groups-functions.php src/bp-groups/bp-groups-functions.php index fb837df..b71482a 100644
function groups_get_current_group() { 696 696 return apply_filters( 'groups_get_current_group', $current_group ); 697 697 } 698 698 699 /** Group Avatars *************************************************************/700 701 /**702 * Generate the avatar upload directory path for a given group.703 *704 * @param int $group_id Optional. ID of the group. Default: ID of the705 * current group.706 * @return string707 */708 function groups_avatar_upload_dir( $group_id = 0 ) {709 global $bp;710 711 if ( !$group_id )712 $group_id = $bp->groups->current_group->id;713 714 $path = bp_core_avatar_upload_path() . '/group-avatars/' . $group_id;715 $newbdir = $path;716 717 if ( !file_exists( $path ) )718 @wp_mkdir_p( $path );719 720 $newurl = bp_core_avatar_url() . '/group-avatars/' . $group_id;721 $newburl = $newurl;722 $newsubdir = '/group-avatars/' . $group_id;723 724 return apply_filters( 'groups_avatar_upload_dir', array( 'path' => $path, 'url' => $newurl, 'subdir' => $newsubdir, 'basedir' => $newbdir, 'baseurl' => $newburl, 'error' => false ) );725 }726 727 699 /** Group Member Status Checks ************************************************/ 728 700 729 701 /** -
src/bp-groups/bp-groups-loader.php
diff --git src/bp-groups/bp-groups-loader.php src/bp-groups/bp-groups-loader.php index d12712f..2314ee9 100644
class BP_Groups_Component extends BP_Component { 269 269 ) 270 270 ) ); 271 271 272 // If avatar uploads are not disabled, add avatar option273 if ( ! (int) $bp->site_options['bp-disable-avatar-uploads'] && $bp->avatar->show_avatars ) {274 $this->group_creation_steps['group-avatar'] = array(275 'name' => _x( 'Photo', 'Group screen nav', 'buddypress' ),276 'position' => 20277 );278 }279 280 272 // If friends component is active, add invitations 281 273 if ( bp_is_active( 'friends' ) ) { 282 274 $this->group_creation_steps['group-invites'] = array( … … class BP_Groups_Component extends BP_Component { 531 523 'position' => 10, 532 524 ), $default_params ); 533 525 534 if ( ! (int) bp_get_option( 'bp-disable-avatar-uploads' ) && buddypress()->avatar->show_avatars ) {535 $sub_nav[] = array_merge( array(536 'name' => __( 'Photo', 'buddypress' ),537 'slug' => 'group-avatar',538 'position' => 20,539 ), $default_params );540 }541 542 526 $sub_nav[] = array_merge( array( 543 527 'name' => __( 'Members', 'buddypress' ), 544 528 'slug' => 'manage-members', -
src/bp-groups/bp-groups-screens.php
diff --git src/bp-groups/bp-groups-screens.php src/bp-groups/bp-groups-screens.php index e89c72b..b81d667 100644
function groups_screen_group_admin_settings() { 660 660 add_action( 'bp_screens', 'groups_screen_group_admin_settings' ); 661 661 662 662 /** 663 * Handle the display of a group's Change Avatar page.664 */665 function groups_screen_group_admin_avatar() {666 667 if ( 'group-avatar' != bp_get_group_current_admin_tab() )668 return false;669 670 // If the logged-in user doesn't have permission or if avatar uploads are disabled, then stop here671 if ( ! bp_is_item_admin() || (int) bp_get_option( 'bp-disable-avatar-uploads' ) || ! buddypress()->avatar->show_avatars )672 return false;673 674 $bp = buddypress();675 676 // If the group admin has deleted the admin avatar677 if ( bp_is_action_variable( 'delete', 1 ) ) {678 679 // Check the nonce680 check_admin_referer( 'bp_group_avatar_delete' );681 682 if ( bp_core_delete_existing_avatar( array( 'item_id' => $bp->groups->current_group->id, 'object' => 'group' ) ) ) {683 bp_core_add_message( __( 'The group profile photo was deleted successfully!', 'buddypress' ) );684 } else {685 bp_core_add_message( __( 'There was a problem deleting the group profile photo; please try again.', 'buddypress' ), 'error' );686 }687 }688 689 if ( ! isset( $bp->avatar_admin ) ) {690 $bp->avatar_admin = new stdClass();691 }692 693 $bp->avatar_admin->step = 'upload-image';694 695 if ( !empty( $_FILES ) ) {696 697 // Check the nonce698 check_admin_referer( 'bp_avatar_upload' );699 700 // Pass the file to the avatar upload handler701 if ( bp_core_avatar_handle_upload( $_FILES, 'groups_avatar_upload_dir' ) ) {702 $bp->avatar_admin->step = 'crop-image';703 704 // Make sure we include the jQuery jCrop file for image cropping705 add_action( 'wp_print_scripts', 'bp_core_add_jquery_cropper' );706 }707 708 }709 710 // If the image cropping is done, crop the image and save a full/thumb version711 if ( isset( $_POST['avatar-crop-submit'] ) ) {712 713 // Check the nonce714 check_admin_referer( 'bp_avatar_cropstore' );715 716 $args = array(717 'object' => 'group',718 'avatar_dir' => 'group-avatars',719 'item_id' => $bp->groups->current_group->id,720 'original_file' => $_POST['image_src'],721 'crop_x' => $_POST['x'],722 'crop_y' => $_POST['y'],723 'crop_w' => $_POST['w'],724 'crop_h' => $_POST['h']725 );726 727 if ( !bp_core_avatar_handle_crop( $args ) ) {728 bp_core_add_message( __( 'There was a problem cropping the group profile photo.', 'buddypress' ), 'error' );729 } else {730 bp_core_add_message( __( 'The new group profile photo was uploaded successfully.', 'buddypress' ) );731 }732 }733 734 do_action( 'groups_screen_group_admin_avatar', $bp->groups->current_group->id );735 736 bp_core_load_template( apply_filters( 'groups_template_group_admin_avatar', 'groups/single/home' ) );737 }738 add_action( 'bp_screens', 'groups_screen_group_admin_avatar' );739 740 /**741 663 * This function handles actions related to member management on the group admin. 742 664 */ 743 665 function groups_screen_group_admin_manage_members() { -
src/bp-loader.php
diff --git src/bp-loader.php src/bp-loader.php index 41c13e0..822253d 100644
class BuddyPress { 301 301 /** Versions **********************************************************/ 302 302 303 303 $this->version = '2.2-alpha'; 304 $this->db_version = 8311;304 $this->db_version = 9131; 305 305 306 306 /** Loading ***********************************************************/ 307 307 … … class BuddyPress { 453 453 require( $this->plugin_dir . 'bp-core/deprecated/1.9.php' ); 454 454 require( $this->plugin_dir . 'bp-core/deprecated/2.0.php' ); 455 455 require( $this->plugin_dir . 'bp-core/deprecated/2.1.php' ); 456 require( $this->plugin_dir . 'bp-core/deprecated/2.2.php' ); 456 457 } 457 458 } 458 459 -
src/bp-members/bp-members-functions.php
diff --git src/bp-members/bp-members-functions.php src/bp-members/bp-members-functions.php index 2f9b1b3..506ac16 100644
function bp_core_delete_account( $user_id = 0 ) { 1168 1168 * @return bool True on success, false on failure. 1169 1169 */ 1170 1170 function bp_core_delete_avatar_on_user_delete( $user_id ) { 1171 return bp_core_delete_existing_avatar( array( 1171 if ( ! bp_is_active( 'attachments' ) ) { 1172 return; 1173 } 1174 1175 return bp_attachments_delete_existing_avatar( array( 1172 1176 'item_id' => $user_id, 1173 1177 'object' => 'user', 1174 1178 ) ); … … function bp_core_map_user_registration( $user_id ) { 1903 1907 add_action( 'user_register', 'bp_core_map_user_registration' ); 1904 1908 1905 1909 /** 1906 * Get the avatar storage directory for use during registration.1907 *1908 * @return string|bool Directory path on success, false on failure.1909 */1910 function bp_core_signup_avatar_upload_dir() {1911 $bp = buddypress();1912 1913 if ( empty( $bp->signup->avatar_dir ) ) {1914 return false;1915 }1916 1917 $path = bp_core_avatar_upload_path() . '/avatars/signups/' . $bp->signup->avatar_dir;1918 $newbdir = $path;1919 1920 if ( ! file_exists( $path ) ) {1921 @wp_mkdir_p( $path );1922 }1923 1924 $newurl = bp_core_avatar_url() . '/avatars/signups/' . $bp->signup->avatar_dir;1925 $newburl = $newurl;1926 $newsubdir = '/avatars/signups/' . $bp->signup->avatar_dir;1927 1928 return apply_filters( 'bp_core_signup_avatar_upload_dir', array(1929 'path' => $path,1930 'url' => $newurl,1931 'subdir' => $newsubdir,1932 'basedir' => $newbdir,1933 'baseurl' => $newburl,1934 'error' => false1935 ) );1936 }1937 1938 /**1939 1910 * Send activation email to a newly registered user. 1940 1911 * 1941 1912 * @param int $user_id ID of the new user. -
src/bp-members/bp-members-screens.php
diff --git src/bp-members/bp-members-screens.php src/bp-members/bp-members-screens.php index 80f5565..aa5ead3 100644
function bp_core_screen_activation() { 235 235 236 236 // grab the key (the old way) 237 237 $key = isset( $_GET['key'] ) ? $_GET['key'] : ''; 238 238 239 239 // grab the key (the new way) 240 240 if ( empty( $key ) ) { 241 241 $key = bp_current_action(); … … function bp_core_screen_activation() { 245 245 if ( empty( $key ) ) { 246 246 return; 247 247 } 248 248 249 249 // Activate the signup 250 250 $user = apply_filters( 'bp_core_activate_account', bp_core_activate_signup( $key ) ); 251 251 … … function bp_core_screen_activation() { 257 257 258 258 $hashed_key = wp_hash( $key ); 259 259 260 // Check if the avatar folder exists. If it does, move rename it, move 261 // it and delete the signup avatar dir 262 if ( file_exists( bp_core_avatar_upload_path() . '/avatars/signups/' . $hashed_key ) ) { 263 @rename( bp_core_avatar_upload_path() . '/avatars/signups/' . $hashed_key, bp_core_avatar_upload_path() . '/avatars/' . $user ); 264 } 260 /** 261 * Please don't use this action, for internal use only 262 */ 263 do_action( 'bp_core_activate_account_avatar', $hashed_key, $user ); 265 264 266 265 bp_core_add_message( __( 'Your account is now active!', 'buddypress' ) ); 267 266 $bp->activation_complete = true; -
src/bp-xprofile/bp-xprofile-actions.php
diff --git src/bp-xprofile/bp-xprofile-actions.php src/bp-xprofile/bp-xprofile-actions.php index d45211e..362fcea 100644
15 15 if ( !defined( 'ABSPATH' ) ) exit; 16 16 17 17 /** 18 * This function runs when an action is set for a screen:19 * example.com/members/andy/profile/change-avatar/ [delete-avatar]20 *21 * The function will delete the active avatar for a user.22 *23 * @package BuddyPress Xprofile24 * @uses bp_core_delete_avatar() Deletes the active avatar for the logged in user.25 * @uses add_action() Runs a specific function for an action when it fires.26 */27 function xprofile_action_delete_avatar() {28 29 if ( !bp_is_user_change_avatar() || !bp_is_action_variable( 'delete-avatar', 0 ) )30 return false;31 32 // Check the nonce33 check_admin_referer( 'bp_delete_avatar_link' );34 35 if ( !bp_is_my_profile() && !bp_current_user_can( 'bp_moderate' ) )36 return false;37 38 if ( bp_core_delete_existing_avatar( array( 'item_id' => bp_displayed_user_id() ) ) )39 bp_core_add_message( __( 'Your profile photo was deleted successfully!', 'buddypress' ) );40 else41 bp_core_add_message( __( 'There was a problem deleting your profile photo; please try again.', 'buddypress' ), 'error' );42 43 bp_core_redirect( wp_get_referer() );44 }45 add_action( 'bp_actions', 'xprofile_action_delete_avatar' );46 47 /**48 18 * Handles the saving of xprofile field visibilities 49 19 * 50 20 * @since BuddyPress (1.9) -
src/bp-xprofile/bp-xprofile-admin.php
diff --git src/bp-xprofile/bp-xprofile-admin.php src/bp-xprofile/bp-xprofile-admin.php index 8c907a4..2eae34f 100644
class BP_XProfile_User_Admin { 585 585 ); 586 586 } 587 587 588 // Avatar Metabox 589 add_meta_box( 590 'bp_xprofile_user_admin_avatar', 591 _x( 'Profile Photo', 'xprofile user-admin edit screen', 'buddypress' ), 592 array( $this, 'user_admin_avatar_metabox' ), 593 $screen_id, 594 'side', 595 'low' 596 ); 588 if ( buddypress()->avatar->show_avatars && ! bp_is_active( 'attachments' ) ) { 589 // Avatar Metabox 590 add_meta_box( 591 'bp_xprofile_user_admin_avatar', 592 _x( 'Profile Photo', 'xprofile user-admin edit screen', 'buddypress' ), 593 array( $this, 'user_admin_avatar_metabox' ), 594 $screen_id, 595 'side', 596 'low' 597 ); 598 } 597 599 } 598 600 599 601 /** … … class BP_XProfile_User_Admin { 606 608 * @since BuddyPress (2.0.0) 607 609 */ 608 610 public function user_admin_load( $doaction = '', $user_id = 0, $request = array(), $redirect_to = '' ) { 609 610 // Eventually delete avatar611 if ( 'delete_avatar' === $doaction ) {612 613 check_admin_referer( 'delete_avatar' );614 615 $redirect_to = remove_query_arg( '_wpnonce', $redirect_to );616 617 if ( bp_core_delete_existing_avatar( array( 'item_id' => $user_id ) ) ) {618 $redirect_to = add_query_arg( 'updated', 'avatar', $redirect_to );619 } else {620 $redirect_to = add_query_arg( 'error', 'avatar', $redirect_to );621 }622 623 bp_core_redirect( $redirect_to );624 625 611 // Update profile fields 626 } elseif ( isset( $_POST['field_ids'] ) ) {612 if ( isset( $_POST['field_ids'] ) ) { 627 613 628 614 // Check the nonce 629 615 check_admin_referer( 'edit-bp-profile_' . $user_id ); … … class BP_XProfile_User_Admin { 834 820 'title' => $user->display_name 835 821 ) ); ?> 836 822 837 <?php if ( bp_get_user_has_avatar( $user->ID ) ) :838 839 $query_args = array(840 'user_id' => $user->ID,841 'action' => 'delete_avatar'842 );843 844 if ( ! empty( $_REQUEST['wp_http_referer'] ) ) {845 $query_args['wp_http_referer'] = urlencode( wp_unslash( $_REQUEST['wp_http_referer'] ) );846 }847 848 $community_url = add_query_arg( $query_args, buddypress()->members->admin->edit_profile_url );849 $delete_link = wp_nonce_url( $community_url, 'delete_avatar' ); ?>850 851 <a href="<?php echo esc_url( $delete_link ); ?>" title="<?php esc_attr_e( 'Delete Profile Photo', 'buddypress' ); ?>" class="bp-xprofile-avatar-user-admin"><?php esc_html_e( 'Delete Profile Photo', 'buddypress' ); ?></a></li>852 853 <?php endif; ?>854 855 823 </div> 856 824 <?php 857 825 } -
src/bp-xprofile/bp-xprofile-functions.php
diff --git src/bp-xprofile/bp-xprofile-functions.php src/bp-xprofile/bp-xprofile-functions.php index f6f2dee..6bede39 100644
function xprofile_override_user_fullnames() { 624 624 add_action( 'bp_setup_globals', 'xprofile_override_user_fullnames', 100 ); 625 625 626 626 /** 627 * Setup the avatar upload directory for a user.628 *629 * @since BuddyPress (1.0.0)630 *631 * @package BuddyPress Core632 *633 * @param string $directory The root directory name. Optional.634 * @param int $user_id The user ID. Optional.635 *636 * @return array() Array containing the path, URL, and other helpful settings.637 */638 function xprofile_avatar_upload_dir( $directory = 'avatars', $user_id = 0 ) {639 640 // Use displayed user if no user ID was passed641 if ( empty( $user_id ) ) {642 $user_id = bp_displayed_user_id();643 }644 645 // Failsafe against accidentally nooped $directory parameter646 if ( empty( $directory ) ) {647 $directory = 'avatars';648 }649 650 $path = bp_core_avatar_upload_path() . '/' . $directory. '/' . $user_id;651 $newbdir = $path;652 653 if ( ! file_exists( $path ) ) {654 @wp_mkdir_p( $path );655 }656 657 $newurl = bp_core_avatar_url() . '/' . $directory. '/' . $user_id;658 $newburl = $newurl;659 $newsubdir = '/' . $directory. '/' . $user_id;660 661 return apply_filters( 'xprofile_avatar_upload_dir', array(662 'path' => $path,663 'url' => $newurl,664 'subdir' => $newsubdir,665 'basedir' => $newbdir,666 'baseurl' => $newburl,667 'error' => false668 ) );669 }670 671 /**672 627 * When search_terms are passed to BP_User_Query, search against xprofile fields. 673 628 * 674 629 * @since BuddyPress (2.0.0) -
src/bp-xprofile/bp-xprofile-loader.php
diff --git src/bp-xprofile/bp-xprofile-loader.php src/bp-xprofile/bp-xprofile-loader.php index 4e9fd67..7a3f596 100644
class BP_XProfile_Component extends BP_Component { 206 206 ); 207 207 208 208 // Change Avatar 209 if ( buddypress()->avatar->show_avatars ) {209 if ( buddypress()->avatar->show_avatars && ! bp_is_active( 'attachments' ) ) { 210 210 $sub_nav[] = array( 211 211 'name' => _x( 'Change Profile Photo', 'Profile header sub menu', 'buddypress' ), 212 212 'slug' => 'change-avatar', 213 213 'parent_url' => $profile_link, 214 214 'parent_slug' => $this->slug, 215 'screen_function' => ' xprofile_screen_change_avatar',215 'screen_function' => 'bp_xprofile_screen_change_gravatar', 216 216 'position' => 30, 217 217 'user_has_access' => bp_core_can_edit_settings() 218 218 ); … … class BP_XProfile_Component extends BP_Component { 301 301 ); 302 302 303 303 // Edit Avatar 304 if ( buddypress()->avatar->show_avatars ) {304 if ( buddypress()->avatar->show_avatars && ! bp_is_active( 'attachments' ) ) { 305 305 $wp_admin_nav[] = array( 306 306 'parent' => 'my-account-' . $this->id, 307 307 'id' => 'my-account-' . $this->id . '-change-avatar', … … class BP_XProfile_Component extends BP_Component { 309 309 'href' => trailingslashit( $profile_link . 'change-avatar' ) 310 310 ); 311 311 } 312 313 312 } 314 313 315 314 parent::setup_admin_bar( $wp_admin_nav ); … … function bp_setup_xprofile() { 376 375 if ( !isset( $bp->profile->id ) ) 377 376 $bp->profile = new BP_XProfile_Component(); 378 377 } 379 add_action( 'bp_setup_components', 'bp_setup_xprofile', 2 ); 380 No newline at end of file 378 add_action( 'bp_setup_components', 'bp_setup_xprofile', 2 ); -
src/bp-xprofile/bp-xprofile-screens.php
diff --git src/bp-xprofile/bp-xprofile-screens.php src/bp-xprofile/bp-xprofile-screens.php index 2b9412e..d53e49a 100644
function xprofile_screen_edit_profile() { 154 154 } 155 155 156 156 /** 157 * Handles the uploading and cropping of a user avatar. Displays the change avatar page.157 * Show the xprofile settings template 158 158 * 159 * @package BuddyPress XProfile 160 * @uses bp_is_my_profile() Checks to make sure the current user being viewed equals the logged in user 161 * @uses bp_core_load_template() Looks for and loads a template file within the current member theme (folder/filename) 159 * @since BuddyPress (2.0.0) 162 160 */ 163 function xprofile_screen_change_avatar() { 164 165 // Bail if not the correct screen 166 if ( !bp_is_my_profile() && !bp_current_user_can( 'bp_moderate' ) ) 167 return false; 161 function bp_xprofile_screen_settings() { 168 162 169 // Bail if there are action variables170 if ( bp_action_variables() ) {163 // Redirect if no privacy settings page is accessible 164 if ( bp_action_variables() || ! bp_is_active( 'xprofile' ) ) { 171 165 bp_do_404(); 172 166 return; 173 167 } 174 168 175 $bp = buddypress(); 176 177 if ( ! isset( $bp->avatar_admin ) ) 178 $bp->avatar_admin = new stdClass(); 179 180 $bp->avatar_admin->step = 'upload-image'; 181 182 if ( !empty( $_FILES ) ) { 183 184 // Check the nonce 185 check_admin_referer( 'bp_avatar_upload' ); 186 187 // Pass the file to the avatar upload handler 188 if ( bp_core_avatar_handle_upload( $_FILES, 'xprofile_avatar_upload_dir' ) ) { 189 $bp->avatar_admin->step = 'crop-image'; 190 191 // Make sure we include the jQuery jCrop file for image cropping 192 add_action( 'wp_print_scripts', 'bp_core_add_jquery_cropper' ); 193 } 194 } 195 196 // If the image cropping is done, crop the image and save a full/thumb version 197 if ( isset( $_POST['avatar-crop-submit'] ) ) { 198 199 // Check the nonce 200 check_admin_referer( 'bp_avatar_cropstore' ); 201 202 $args = array( 203 'item_id' => bp_displayed_user_id(), 204 'original_file' => $_POST['image_src'], 205 'crop_x' => $_POST['x'], 206 'crop_y' => $_POST['y'], 207 'crop_w' => $_POST['w'], 208 'crop_h' => $_POST['h'] 209 ); 210 211 if ( ! bp_core_avatar_handle_crop( $args ) ) { 212 bp_core_add_message( __( 'There was a problem cropping your profile photo.', 'buddypress' ), 'error' ); 213 } else { 214 do_action( 'xprofile_avatar_uploaded' ); 215 bp_core_add_message( __( 'Your new profile photo was uploaded successfully.', 'buddypress' ) ); 216 bp_core_redirect( bp_displayed_user_domain() ); 217 } 218 } 219 220 do_action( 'xprofile_screen_change_avatar' ); 221 222 bp_core_load_template( apply_filters( 'xprofile_template_change_avatar', 'members/single/home' ) ); 169 // Load the template 170 bp_core_load_template( apply_filters( 'bp_settings_screen_xprofile', '/members/single/settings/profile' ) ); 223 171 } 224 172 225 173 /** 226 * Show the xprofile settingstemplate174 * Show the xprofile change Gravatar template 227 175 * 228 * @since BuddyPress (2. 0.0)176 * @since BuddyPress (2.2.0) 229 177 */ 230 function bp_xprofile_screen_settings() { 178 function bp_xprofile_screen_change_gravatar() { 179 if ( ! bp_is_my_profile() && ! bp_current_user_can( 'bp_moderate' ) ) { 180 return false; 181 } 231 182 232 // Redirect if no privacy settings page is accessible233 if ( bp_action_variables() || ! bp_is_active( 'xprofile' )) {183 // Bail if there are action variables 184 if ( bp_action_variables() ) { 234 185 bp_do_404(); 235 186 return; 236 187 } 237 188 238 // Load the template 239 bp_core_load_template( apply_filters( 'bp_settings_screen_xprofile', '/members/single/settings/profile' ) ); 189 bp_core_load_template( apply_filters( 'bp_xprofile_screen_change_gravatar', 'members/single/home' ) ); 240 190 } -
tests/phpunit/includes/install.php
diff --git tests/phpunit/includes/install.php tests/phpunit/includes/install.php index 2c297e3..d7a0398 100644
define( 'BP_ROOT_BLOG', 1 ); 26 26 tests_add_filter( 'show_admin_bar', '__return_true' ); 27 27 28 28 function wp_test_bp_install( $value ) { 29 return array( 'activity' => 1, ' blogs' => 1, 'friends' => 1, 'groups' => 1, 'members' => 1, 'messages' => 1, 'notifications' => 1, 'settings' => 1, 'xprofile' => 1, );29 return array( 'activity' => 1, 'attachments' => 1, 'blogs' => 1, 'friends' => 1, 'groups' => 1, 'members' => 1, 'messages' => 1, 'notifications' => 1, 'settings' => 1, 'xprofile' => 1, ); 30 30 } 31 31 tests_add_filter( 'bp_new_install_default_components', 'wp_test_bp_install' ); 32 32 -
tests/phpunit/testcases/core/avatars.php
diff --git tests/phpunit/testcases/core/avatars.php tests/phpunit/testcases/core/avatars.php index 0c5254a..d822c9f 100644
class BP_Tests_Avatars extends BP_UnitTestCase { 28 28 $avatar_dir = 'group-avatars'; 29 29 } 30 30 31 $this->rrmdir( bp_ core_avatar_upload_path() . '/' . $avatar_dir );31 $this->rrmdir( bp_attachments_get_upload_dir() . '/' . $avatar_dir ); 32 32 } 33 33 34 34 private function rrmdir( $dir ) { … … class BP_Tests_Avatars extends BP_UnitTestCase { 79 79 $this->go_to( get_blog_option( $blog_id, 'siteurl' ) ); 80 80 81 81 // test to see if the upload dir is correct 82 $this->assertEquals( $upload_dir['baseurl'], bp_ core_avatar_url() );82 $this->assertEquals( $upload_dir['baseurl'], bp_attachments_get_upload_dir( 'url' ) ); 83 83 84 84 // reset globals 85 85 $this->go_to( '/' );