| | 1 | <?php |
| | 2 | |
| | 3 | /** |
| | 4 | * Class WP_Site_Icon. |
| | 5 | * |
| | 6 | * @since 4.3.0 |
| | 7 | */ |
| | 8 | class WP_Site_Icon { |
| | 9 | |
| | 10 | /** |
| | 11 | * The minimum size of the site icon. |
| | 12 | * |
| | 13 | * @since 4.3.0 |
| | 14 | * |
| | 15 | * @var int |
| | 16 | */ |
| | 17 | public $min_size = 512; |
| | 18 | |
| | 19 | /** |
| | 20 | * The size to which to crop the image so that we can display it in the UI nicely. |
| | 21 | * |
| | 22 | * @since 4.3.0 |
| | 23 | * |
| | 24 | * @var int |
| | 25 | */ |
| | 26 | public $page_crop = 512; |
| | 27 | |
| | 28 | /** |
| | 29 | * |
| | 30 | * @since 4.3.0 |
| | 31 | * |
| | 32 | * @var array |
| | 33 | */ |
| | 34 | public $site_icon_sizes = array( |
| | 35 | /** |
| | 36 | * Square, medium sized tiles for IE11+. |
| | 37 | * |
| | 38 | * @link https://msdn.microsoft.com/library/dn455106(v=vs.85).aspx |
| | 39 | */ |
| | 40 | 270, |
| | 41 | |
| | 42 | /** |
| | 43 | * App icons up to iPhone 6 Plus. |
| | 44 | * |
| | 45 | * @link https://developer.apple.com/library/prerelease/ios/documentation/UserExperience/Conceptual/MobileHIG/IconMatrix.html |
| | 46 | */ |
| | 47 | 180, |
| | 48 | |
| | 49 | // Our regular Favicon. |
| | 50 | 32, |
| | 51 | ); |
| | 52 | |
| | 53 | /** |
| | 54 | * Register our actions and filters. |
| | 55 | * |
| | 56 | * @since 4.3.0 |
| | 57 | */ |
| | 58 | public function __construct() { |
| | 59 | |
| | 60 | // Add the favicon to the backend. |
| | 61 | add_action( 'admin_head', 'wp_site_icon' ); |
| | 62 | |
| | 63 | add_action( 'admin_menu', array( $this, 'admin_menu_upload_site_icon' ) ); |
| | 64 | |
| | 65 | add_action( 'admin_action_set_site_icon', array( $this, 'set_site_icon' ) ); |
| | 66 | add_action( 'admin_action_remove_site_icon', array( $this, 'remove_site_icon' ) ); |
| | 67 | |
| | 68 | add_action( 'delete_attachment', array( $this, 'delete_attachment_data' ), 10, 1 ); |
| | 69 | add_filter( 'get_post_metadata', array( $this, 'get_post_metadata' ), 10, 4 ); |
| | 70 | } |
| | 71 | |
| | 72 | /** |
| | 73 | * Add a hidden upload page. |
| | 74 | * |
| | 75 | * There is no need to access it directly. |
| | 76 | * |
| | 77 | * @since 4.3.0 |
| | 78 | */ |
| | 79 | public function admin_menu_upload_site_icon() { |
| | 80 | $hook = add_submenu_page( null, __( 'Site Icon' ), __( 'Site Icon' ), 'manage_options', 'site-icon', array( $this, 'upload_site_icon_page' ) ); |
| | 81 | |
| | 82 | add_action( "load-$hook", array( $this, 'add_upload_settings' ) ); |
| | 83 | add_action( "admin_print_scripts-$hook", array( $this, 'enqueue_scripts' ) ); |
| | 84 | } |
| | 85 | |
| | 86 | /** |
| | 87 | * Add scripts to admin settings pages. |
| | 88 | * |
| | 89 | * @since 4.3.0 |
| | 90 | */ |
| | 91 | public function enqueue_scripts() { |
| | 92 | wp_enqueue_style( 'jcrop' ); |
| | 93 | wp_enqueue_script( 'site-icon-crop' ); |
| | 94 | } |
| | 95 | |
| | 96 | /** |
| | 97 | * Load on when the admin is initialized. |
| | 98 | * |
| | 99 | * @since 4.3.0 |
| | 100 | */ |
| | 101 | public function add_upload_settings() { |
| | 102 | add_settings_section( 'site-icon-upload', false, false, 'site-icon-upload' ); |
| | 103 | add_settings_field( 'site-icon-upload', __( 'Upload Image' ), array( $this, 'upload_field' ), 'site-icon-upload', 'site-icon-upload', array( |
| | 104 | 'label_for' => 'site-icon-upload', |
| | 105 | ) ); |
| | 106 | } |
| | 107 | |
| | 108 | /** |
| | 109 | * Removes site icon. |
| | 110 | * |
| | 111 | * @since 4.3.0 |
| | 112 | */ |
| | 113 | public function remove_site_icon() { |
| | 114 | check_admin_referer( 'remove-site-icon' ); |
| | 115 | |
| | 116 | $this->delete_site_icon(); |
| | 117 | |
| | 118 | add_settings_error( 'site-icon', 'icon-removed', __( 'Site Icon removed.' ), 'updated' ); |
| | 119 | } |
| | 120 | |
| | 121 | /** |
| | 122 | * Uploading a site_icon is a 3 step process |
| | 123 | * |
| | 124 | * 1. Select the file to upload |
| | 125 | * 2. Crop the file |
| | 126 | * 3. Confirmation |
| | 127 | * |
| | 128 | * @since 4.3.0 |
| | 129 | */ |
| | 130 | public function upload_site_icon_page() { |
| | 131 | $action = isset( $_REQUEST['action'] ) ? $_REQUEST['action'] : 'select_site_icon'; |
| | 132 | |
| | 133 | switch ( $action ) { |
| | 134 | case 'select_site_icon': |
| | 135 | $this->select_page(); |
| | 136 | break; |
| | 137 | |
| | 138 | case 'crop_site_icon': |
| | 139 | $this->crop_page(); |
| | 140 | break; |
| | 141 | |
| | 142 | default: |
| | 143 | wp_safe_redirect( admin_url( 'options-general.php#site-icon' ) ); |
| | 144 | exit; |
| | 145 | } |
| | 146 | } |
| | 147 | |
| | 148 | /** |
| | 149 | * Displays the site_icon form to upload the image. |
| | 150 | * |
| | 151 | * @since 4.3.0 |
| | 152 | */ |
| | 153 | public function select_page() { |
| | 154 | ?> |
| | 155 | <div class="wrap"> |
| | 156 | <h2><?php _e( 'Add Site Icon' ); ?></h2> |
| | 157 | <?php settings_errors( 'site-icon' ); ?> |
| | 158 | <?php do_settings_sections( 'site-icon-upload' ); ?> |
| | 159 | </div> |
| | 160 | <?php |
| | 161 | } |
| | 162 | |
| | 163 | /** |
| | 164 | * Settings field for file upload. |
| | 165 | * |
| | 166 | * @since 4.3.0 |
| | 167 | */ |
| | 168 | public function upload_field() { |
| | 169 | wp_enqueue_media(); |
| | 170 | wp_enqueue_script( 'site-icon' ); |
| | 171 | wp_dequeue_script( 'site-icon-crop' ); |
| | 172 | |
| | 173 | $update_url = esc_url( add_query_arg( array( |
| | 174 | 'page' => 'site-icon', |
| | 175 | 'action' => 'crop_site_icon', |
| | 176 | ), wp_nonce_url( admin_url( 'options-general.php' ), 'crop-site-icon' ) ) ); |
| | 177 | ?> |
| | 178 | <p class="hide-if-no-js"> |
| | 179 | <label class="screen-reader-text" for="choose-from-library-link"><?php _e( 'Choose an image from your media library:' ); ?></label> |
| | 180 | <button type="button" id="choose-from-library-link" class="button" data-update-link="<?php echo esc_attr( $update_url ); ?>" data-choose="<?php esc_attr_e( 'Choose a Site Icon' ); ?>" data-update="<?php esc_attr_e( 'Set as Site Icon' ); ?>"><?php _e( 'Choose Image' ); ?></button> |
| | 181 | </p> |
| | 182 | <form class="hide-if-js" action="<?php echo esc_url( admin_url( 'options-general.php?page=site-icon' ) ); ?>" method="post" enctype="multipart/form-data"> |
| | 183 | <input name="action" value="crop_site_icon" type="hidden" /> |
| | 184 | <input name="site-icon" type="file" /> |
| | 185 | <input name="submit" value="<?php esc_attr_e( 'Upload Image' ); ?>" type="submit" class="button button-primary" /> |
| | 186 | <p class="description"> |
| | 187 | <?php printf( __( 'The image is recommended to be a square image of at least %spx in both width and height.' ), "<strong>$this->min_size</strong>" ); ?> |
| | 188 | </p> |
| | 189 | <?php wp_nonce_field( 'crop-site-icon' ); ?> |
| | 190 | </form> |
| | 191 | <?php |
| | 192 | } |
| | 193 | |
| | 194 | /** |
| | 195 | * Crop a the image admin view. |
| | 196 | * |
| | 197 | * @since 4.3.0 |
| | 198 | */ |
| | 199 | public function crop_page() { |
| | 200 | check_admin_referer( 'crop-site-icon' ); |
| | 201 | |
| | 202 | if ( isset( $_GET['file'] ) ) { |
| | 203 | $attachment_id = absint( $_GET['file'] ); |
| | 204 | $file = get_attached_file( $attachment_id, true ); |
| | 205 | $url = wp_get_attachment_image_src( $attachment_id, 'full' ); |
| | 206 | $url = $url[0]; |
| | 207 | } else { |
| | 208 | $upload = $this->handle_upload(); |
| | 209 | $attachment_id = $upload['attachment_id']; |
| | 210 | $file = $upload['file']; |
| | 211 | $url = $upload['url']; |
| | 212 | } |
| | 213 | |
| | 214 | $image_size = getimagesize( $file ); |
| | 215 | |
| | 216 | if ( $image_size[0] < $this->min_size ) { |
| | 217 | add_settings_error( 'site-icon', 'too-small', sprintf( __( 'The selected image is smaller than %upx in width.' ), $this->min_size ) ); |
| | 218 | |
| | 219 | // back to step one |
| | 220 | $this->select_page(); |
| | 221 | |
| | 222 | return; |
| | 223 | } |
| | 224 | |
| | 225 | if ( $image_size[1] < $this->min_size ) { |
| | 226 | add_settings_error( 'site-icon', 'too-small', sprintf( __( 'The selected image is smaller than %upx in height.' ), $this->min_size ) ); |
| | 227 | |
| | 228 | // Back to step one. |
| | 229 | $this->select_page(); |
| | 230 | |
| | 231 | return; |
| | 232 | } |
| | 233 | |
| | 234 | // Let's resize the image so that the user can easier crop a image that in the admin view. |
| | 235 | $crop_height = absint( $this->page_crop * $image_size[1] / $image_size[0] ); |
| | 236 | $cropped = wp_crop_image( $attachment_id, 0, 0, 0, 0, $this->page_crop, $crop_height ); |
| | 237 | if ( ! $cropped || is_wp_error( $cropped ) ) { |
| | 238 | wp_die( __( 'Image could not be processed. Please go back and try again.' ), __( 'Image Processing Error' ) ); |
| | 239 | } |
| | 240 | $cropped_size = getimagesize( $cropped ); |
| | 241 | |
| | 242 | // set default values (in case of no JS) |
| | 243 | $crop_ratio = $image_size[0] / $cropped_size[0]; |
| | 244 | if ( $cropped_size[0] < $cropped_size[1] ) { |
| | 245 | $crop_x = 0; |
| | 246 | $crop_y = absint( ( $cropped_size[1] - $cropped_size[0] ) / 2 ); |
| | 247 | $crop_size = $cropped_size[0]; |
| | 248 | } elseif ( $cropped_size[0] > $cropped_size[1] ) { |
| | 249 | $crop_x = absint( ( $cropped_size[0] - $cropped_size[1] ) / 2 ); |
| | 250 | $crop_y = 0; |
| | 251 | $crop_size = $cropped_size[1]; |
| | 252 | } else { |
| | 253 | $crop_x = 0; |
| | 254 | $crop_y = 0; |
| | 255 | $crop_size = $cropped_size[0]; |
| | 256 | } |
| | 257 | |
| | 258 | wp_delete_file( $cropped ); |
| | 259 | |
| | 260 | wp_localize_script( 'site-icon-crop', 'wpSiteIconCropData', $this->initial_crop_data( $crop_ratio, $cropped_size ) ); |
| | 261 | ?> |
| | 262 | |
| | 263 | <div class="wrap"> |
| | 264 | <h2 class="site-icon-title"><?php esc_html_e( 'Site Icon' ); ?></h2> |
| | 265 | <?php settings_errors( 'site-icon' ); ?> |
| | 266 | |
| | 267 | <div class="site-icon-crop-shell"> |
| | 268 | <form action="options-general.php" method="post" enctype="multipart/form-data"> |
| | 269 | <p class="hide-if-no-js description"><?php _e('Choose the part of the image you want to use as your site icon.'); ?></p> |
| | 270 | <p class="hide-if-js description"><strong><?php _e( 'You need Javascript to choose a part of the image.'); ?></strong></p> |
| | 271 | |
| | 272 | <div class="site-icon-crop-preview-shell hide-if-no-js"> |
| | 273 | <h3><?php esc_html_e( 'Preview' ); ?></h3> |
| | 274 | <strong><?php esc_html_e( 'As your favicon' ); ?></strong> |
| | 275 | <div class="site-icon-crop-favicon-preview-shell"> |
| | 276 | <img src="images/browser.png" class="site-icon-browser-preview" width="172" height="79" alt="<?php esc_attr_e( 'Browser Chrome' ); ?>"/> |
| | 277 | |
| | 278 | <div class="site-icon-crop-preview-favicon"> |
| | 279 | <img src="<?php echo esc_url( $url ); ?>" id="preview-favicon" alt="<?php esc_attr_e( 'Preview Favicon' ); ?>"/> |
| | 280 | </div> |
| | 281 | <span class="site-icon-browser-title"><?php bloginfo( 'name' ); ?></span> |
| | 282 | </div> |
| | 283 | |
| | 284 | <strong><?php esc_html_e( 'As a mobile icon' ); ?></strong> |
| | 285 | <div class="site-icon-crop-preview-homeicon"> |
| | 286 | <img src="<?php echo esc_url( $url ); ?>" id="preview-homeicon" alt="<?php esc_attr_e( 'Preview Home Icon' ); ?>"/> |
| | 287 | </div> |
| | 288 | </div> |
| | 289 | <img src="<?php echo esc_url( $url ); ?>" id="crop-image" class="site-icon-crop-image" width="<?php echo esc_attr( $cropped_size[0] ); ?>" height="<?php echo esc_attr( $cropped_size[1] ); ?>" alt="<?php esc_attr_e( 'Image to be cropped' ); ?>"/> |
| | 290 | |
| | 291 | <input type="hidden" id="crop-x" name="crop-x" value="<?php echo esc_attr( $crop_x ); ?>" /> |
| | 292 | <input type="hidden" id="crop-y" name="crop-y" value="<?php echo esc_attr( $crop_y ); ?>" /> |
| | 293 | <input type="hidden" id="crop-width" name="crop-w" value="<?php echo esc_attr( $crop_size ); ?>" /> |
| | 294 | <input type="hidden" id="crop-height" name="crop-h" value="<?php echo esc_attr( $crop_size ); ?>" /> |
| | 295 | |
| | 296 | <input type="hidden" name="action" value="set_site_icon" /> |
| | 297 | <input type="hidden" name="attachment_id" value="<?php echo esc_attr( $attachment_id ); ?>" /> |
| | 298 | <input type="hidden" name="crop_ratio" value="<?php echo esc_attr( $crop_ratio ); ?>" /> |
| | 299 | <?php if ( empty( $_POST ) && isset( $_GET['file'] ) ) : ?> |
| | 300 | <input type="hidden" name="create-new-attachment" value="true" /> |
| | 301 | <?php endif; ?> |
| | 302 | <?php wp_nonce_field( 'set-site-icon' ); ?> |
| | 303 | |
| | 304 | <p class="submit"> |
| | 305 | <?php submit_button( __( 'Crop and Publish' ), 'primary hide-if-no-js', 'submit', false ); ?> |
| | 306 | <?php submit_button( __( 'Publish' ), 'primary hide-if-js', 'submit', false ); ?> |
| | 307 | <a class="button secondary" href="options-general.php"><?php _e( 'Cancel' ); ?></a> |
| | 308 | </p> |
| | 309 | </form> |
| | 310 | </div> |
| | 311 | </div> |
| | 312 | <?php |
| | 313 | } |
| | 314 | |
| | 315 | /** |
| | 316 | * Saves a new Site Icon. |
| | 317 | * |
| | 318 | * @since 4.3.0 |
| | 319 | */ |
| | 320 | public function set_site_icon() { |
| | 321 | check_admin_referer( 'set-site-icon' ); |
| | 322 | |
| | 323 | // Delete any existing site icon images. |
| | 324 | $this->delete_site_icon(); |
| | 325 | |
| | 326 | $attachment_id = absint( $_POST['attachment_id'] ); |
| | 327 | |
| | 328 | // TODO |
| | 329 | if ( empty( $_POST['skip-cropping'] ) ) { |
| | 330 | $crop_ratio = (float) $_POST['crop_ratio']; |
| | 331 | $crop_data = $this->convert_coordinates_from_resized_to_full( $_POST['crop-x'], $_POST['crop-y'], $_POST['crop-w'], $_POST['crop-h'], $crop_ratio ); |
| | 332 | $cropped = wp_crop_image( $attachment_id, $crop_data['crop_x'], $crop_data['crop_y'], $crop_data['crop_width'], $crop_data['crop_height'], $this->min_size, $this->min_size ); |
| | 333 | } elseif ( ! empty( $_POST['create-new-attachment'] ) ) { |
| | 334 | $cropped = _copy_image_file( $attachment_id ); |
| | 335 | } else { |
| | 336 | $cropped = get_attached_file( $attachment_id ); |
| | 337 | } |
| | 338 | |
| | 339 | if ( ! $cropped || is_wp_error( $cropped ) ) { |
| | 340 | wp_die( __( 'Image could not be processed. Please go back and try again.' ), __( 'Image Processing Error' ) ); |
| | 341 | } |
| | 342 | |
| | 343 | $object = $this->create_attachment_object( $cropped, $attachment_id ); |
| | 344 | |
| | 345 | if ( ! empty( $_POST['create-new-attachment'] ) ) { |
| | 346 | unset( $object['ID'] ); |
| | 347 | } |
| | 348 | |
| | 349 | // Update the attachment |
| | 350 | add_filter( 'intermediate_image_sizes_advanced', array( $this, 'additional_sizes' ) ); |
| | 351 | $attachment_id = $this->insert_attachment( $object, $cropped ); |
| | 352 | remove_filter( 'intermediate_image_sizes_advanced', array( $this, 'additional_sizes' ) ); |
| | 353 | |
| | 354 | // Save the site_icon data into option |
| | 355 | update_option( 'site_icon', $attachment_id ); |
| | 356 | |
| | 357 | add_settings_error( 'site-icon', 'icon-updated', __( 'Site Icon updated.' ), 'updated' ); |
| | 358 | } |
| | 359 | |
| | 360 | /** |
| | 361 | * This function is used to pass data to the localize script |
| | 362 | * so that we can center the cropper and also set the minimum |
| | 363 | * cropper if we still want to show the |
| | 364 | * |
| | 365 | * @since 4.3.0 |
| | 366 | * |
| | 367 | * @param float $ratio |
| | 368 | * @param array $cropped_size |
| | 369 | * @return array |
| | 370 | */ |
| | 371 | public function initial_crop_data( $ratio, $cropped_size ) { |
| | 372 | $init_x = $init_y = $init_size = 0; |
| | 373 | |
| | 374 | $min_crop_size = ( $this->min_size / $ratio ); |
| | 375 | $resized_width = $cropped_size[0]; |
| | 376 | $resized_height = $cropped_size[1]; |
| | 377 | |
| | 378 | // Landscape format ( width > height ) |
| | 379 | if ( $resized_width > $resized_height ) { |
| | 380 | $init_x = ( $this->page_crop - $resized_height ) / 2; |
| | 381 | $init_size = $resized_height; |
| | 382 | } |
| | 383 | |
| | 384 | // Portrait format ( height > width ) |
| | 385 | if ( $resized_width < $resized_height ) { |
| | 386 | $init_y = ( $this->page_crop - $resized_width ) / 2; |
| | 387 | $init_size = $resized_height; |
| | 388 | } |
| | 389 | |
| | 390 | // Square height == width |
| | 391 | if ( $resized_width == $resized_height ) { |
| | 392 | $init_size = $resized_height; |
| | 393 | } |
| | 394 | |
| | 395 | return array( |
| | 396 | 'init_x' => $init_x, |
| | 397 | 'init_y' => $init_y, |
| | 398 | 'init_size' => $init_size, |
| | 399 | 'min_size' => $min_crop_size, |
| | 400 | ); |
| | 401 | } |
| | 402 | |
| | 403 | /** |
| | 404 | * Converts the coordinates from the downsized image to the original image for accurate cropping. |
| | 405 | * |
| | 406 | * @since 4.3.0 |
| | 407 | * |
| | 408 | * @param int $crop_x |
| | 409 | * @param int $crop_y |
| | 410 | * @param int $crop_width |
| | 411 | * @param int $crop_height |
| | 412 | * @param float $ratio |
| | 413 | * @return array |
| | 414 | */ |
| | 415 | public function convert_coordinates_from_resized_to_full( $crop_x, $crop_y, $crop_width, $crop_height, $ratio ) { |
| | 416 | return array( |
| | 417 | 'crop_x' => floor( $crop_x * $ratio ), |
| | 418 | 'crop_y' => floor( $crop_y * $ratio ), |
| | 419 | 'crop_width' => floor( $crop_width * $ratio ), |
| | 420 | 'crop_height' => floor( $crop_height * $ratio ), |
| | 421 | ); |
| | 422 | } |
| | 423 | |
| | 424 | /** |
| | 425 | * Upload the file to be cropped in the second step. |
| | 426 | * |
| | 427 | * @since 4.3.0 |
| | 428 | */ |
| | 429 | public function handle_upload() { |
| | 430 | $uploaded_file = $_FILES['site-icon']; |
| | 431 | $file_type = wp_check_filetype_and_ext( $uploaded_file['tmp_name'], $uploaded_file['name'] ); |
| | 432 | if ( ! wp_match_mime_types( 'image', $file_type['type'] ) ) { |
| | 433 | wp_die( __( 'The uploaded file is not a valid image. Please try again.' ) ); |
| | 434 | } |
| | 435 | |
| | 436 | $file = wp_handle_upload( $uploaded_file, array( 'test_form' => false ) ); |
| | 437 | |
| | 438 | if ( isset( $file['error'] ) ) { |
| | 439 | wp_die( $file['error'], __( 'Image Upload Error' ) ); |
| | 440 | } |
| | 441 | |
| | 442 | $url = $file['url']; |
| | 443 | $type = $file['type']; |
| | 444 | $file = $file['file']; |
| | 445 | $filename = basename( $file ); |
| | 446 | |
| | 447 | // Construct the object array |
| | 448 | $object = array( |
| | 449 | 'post_title' => $filename, |
| | 450 | 'post_content' => $url, |
| | 451 | 'post_mime_type' => $type, |
| | 452 | 'guid' => $url, |
| | 453 | 'context' => 'site-icon', |
| | 454 | ); |
| | 455 | |
| | 456 | // Save the data |
| | 457 | $attachment_id = wp_insert_attachment( $object, $file ); |
| | 458 | |
| | 459 | return compact( 'attachment_id', 'file', 'filename', 'url', 'type' ); |
| | 460 | } |
| | 461 | |
| | 462 | /** |
| | 463 | * Create an attachment 'object'. |
| | 464 | * |
| | 465 | * @since 4.3.0 |
| | 466 | * |
| | 467 | * @param string $cropped Cropped image URL. |
| | 468 | * @param int $parent_attachment_id Attachment ID of parent image. |
| | 469 | * @return array Attachment object. |
| | 470 | */ |
| | 471 | public function create_attachment_object( $cropped, $parent_attachment_id ) { |
| | 472 | $parent = get_post( $parent_attachment_id ); |
| | 473 | $parent_url = $parent->guid; |
| | 474 | $url = str_replace( basename( $parent_url ), basename( $cropped ), $parent_url ); |
| | 475 | |
| | 476 | $size = @getimagesize( $cropped ); |
| | 477 | $image_type = ( $size ) ? $size['mime'] : 'image/jpeg'; |
| | 478 | |
| | 479 | $object = array( |
| | 480 | 'ID' => $parent_attachment_id, |
| | 481 | 'post_title' => basename( $cropped ), |
| | 482 | 'post_content' => $url, |
| | 483 | 'post_mime_type' => $image_type, |
| | 484 | 'guid' => $url, |
| | 485 | 'context' => 'site-icon' |
| | 486 | ); |
| | 487 | |
| | 488 | return $object; |
| | 489 | } |
| | 490 | |
| | 491 | /** |
| | 492 | * Insert an attachment and its metadata. |
| | 493 | * |
| | 494 | * @since 4.3.0 |
| | 495 | * |
| | 496 | * @param array $object Attachment object. |
| | 497 | * @param string $cropped Cropped image URL. |
| | 498 | * @return int Attachment ID. |
| | 499 | */ |
| | 500 | public function insert_attachment( $object, $cropped ) { |
| | 501 | $attachment_id = wp_insert_attachment( $object, $cropped ); |
| | 502 | $metadata = wp_generate_attachment_metadata( $attachment_id, $cropped ); |
| | 503 | |
| | 504 | /** |
| | 505 | * Filter the site icon attachment metadata. |
| | 506 | * |
| | 507 | * @since 4.3.0 |
| | 508 | * |
| | 509 | * @see wp_generate_attachment_metadata() |
| | 510 | * |
| | 511 | * @param array $metadata Attachment metadata. |
| | 512 | */ |
| | 513 | $metadata = apply_filters( 'site_icon_attachment_metadata', $metadata ); |
| | 514 | wp_update_attachment_metadata( $attachment_id, $metadata ); |
| | 515 | |
| | 516 | return $attachment_id; |
| | 517 | } |
| | 518 | |
| | 519 | /** |
| | 520 | * Add additional sizes to be made when creating the site_icon images. |
| | 521 | * |
| | 522 | * @since 4.3.0 |
| | 523 | * |
| | 524 | * @param array $sizes |
| | 525 | * @return array |
| | 526 | */ |
| | 527 | public function additional_sizes( $sizes = array() ) { |
| | 528 | $only_crop_sizes = array(); |
| | 529 | |
| | 530 | /** |
| | 531 | * Filters the different dimensions that a site icon is saved in. |
| | 532 | * |
| | 533 | * @since 4.3.0 |
| | 534 | * |
| | 535 | * @param array $site_icon_sizes Sizes available for the Site Icon. |
| | 536 | */ |
| | 537 | $this->site_icon_sizes = apply_filters( 'site_icon_image_sizes', $this->site_icon_sizes ); |
| | 538 | // use a natural sort of numbers |
| | 539 | natsort( $this->site_icon_sizes ); |
| | 540 | $this->site_icon_sizes = array_reverse( $this->site_icon_sizes ); |
| | 541 | |
| | 542 | // ensure that we only resize the image into |
| | 543 | foreach ( $sizes as $name => $size_array ) { |
| | 544 | if ( $size_array['crop'] ) { |
| | 545 | $only_crop_sizes[ $name ] = $size_array; |
| | 546 | } |
| | 547 | } |
| | 548 | |
| | 549 | foreach ( $this->site_icon_sizes as $size ) { |
| | 550 | if ( $size < $this->min_size ) { |
| | 551 | $only_crop_sizes[ 'site_icon-' . $size ] = array( |
| | 552 | 'width ' => $size, |
| | 553 | 'height' => $size, |
| | 554 | 'crop' => true, |
| | 555 | ); |
| | 556 | } |
| | 557 | } |
| | 558 | |
| | 559 | return $only_crop_sizes; |
| | 560 | } |
| | 561 | |
| | 562 | /** |
| | 563 | * Add Site Icon sizes to the array of image sizes on demand. |
| | 564 | * |
| | 565 | * @since 4.3.0 |
| | 566 | * |
| | 567 | * @param array $sizes |
| | 568 | * @return array |
| | 569 | */ |
| | 570 | public function intermediate_image_sizes( $sizes = array() ) { |
| | 571 | /** This filter is documented in wp-admin/site-icon.php */ |
| | 572 | $this->site_icon_sizes = apply_filters( 'site_icon_image_sizes', $this->site_icon_sizes ); |
| | 573 | foreach ( $this->site_icon_sizes as $size ) { |
| | 574 | $sizes[] = 'site_icon-' . $size; |
| | 575 | } |
| | 576 | |
| | 577 | return $sizes; |
| | 578 | } |
| | 579 | |
| | 580 | /** |
| | 581 | * Deletes all additional image sizes, used for site icons. |
| | 582 | * |
| | 583 | * @since 4.3.0 |
| | 584 | * |
| | 585 | * @return bool |
| | 586 | */ |
| | 587 | public function delete_site_icon() { |
| | 588 | // We add the filter to make sure that we also delete all the added images |
| | 589 | add_filter( 'intermediate_image_sizes', array( $this, 'intermediate_image_sizes' ) ); |
| | 590 | wp_delete_attachment( get_option( 'site_icon' ), true ); |
| | 591 | remove_filter( 'intermediate_image_sizes', array( $this, 'intermediate_image_sizes' ) ); |
| | 592 | |
| | 593 | return delete_option( 'site_icon' ); |
| | 594 | } |
| | 595 | |
| | 596 | /** |
| | 597 | * Deletes the Site Icon when the image file is deleted. |
| | 598 | * |
| | 599 | * @since 4.3.0 |
| | 600 | * |
| | 601 | * @param int $post_id Attachment ID. |
| | 602 | */ |
| | 603 | public function delete_attachment_data( $post_id ) { |
| | 604 | // The user could be deleting the site_icon image |
| | 605 | $site_icon_id = get_option( 'site_icon' ); |
| | 606 | |
| | 607 | if ( $site_icon_id && $post_id == $site_icon_id ) { |
| | 608 | delete_option( 'site_icon' ); |
| | 609 | } |
| | 610 | } |
| | 611 | |
| | 612 | /** |
| | 613 | * Adds custom image sizes when meta data for an image is requested, that happens to be used as Site Icon. |
| | 614 | * |
| | 615 | * @since 4.3.0 |
| | 616 | * |
| | 617 | * @param null|array|string $value The value get_metadata() should |
| | 618 | * return - a single metadata value, |
| | 619 | * or an array of values. |
| | 620 | * @param int $post_id Post ID. |
| | 621 | * @param string $meta_key Meta key. |
| | 622 | * @param string|array $single Meta value, or an array of values. |
| | 623 | * @return array|null|string |
| | 624 | */ |
| | 625 | public function get_post_metadata( $value, $post_id, $meta_key, $single ) { |
| | 626 | $site_icon_id = get_option( 'site_icon' ); |
| | 627 | |
| | 628 | if ( $post_id == $site_icon_id && '_wp_attachment_backup_sizes' == $meta_key && $single ) { |
| | 629 | add_filter( 'intermediate_image_sizes', array( $this, 'intermediate_image_sizes' ) ); |
| | 630 | } |
| | 631 | |
| | 632 | return $value; |
| | 633 | } |
| | 634 | } |
| | 635 | |
| | 636 | $GLOBALS['wp_site_icon'] = new WP_Site_Icon; |