| 1 | <?php |
|---|
| 2 | |
|---|
| 3 | class WP_Site_Icon_Admin_UI { |
|---|
| 4 | /** |
|---|
| 5 | * The size to which to crop the image so that we can display it in the UI nicely. |
|---|
| 6 | * |
|---|
| 7 | * @since 4.3.0 |
|---|
| 8 | * |
|---|
| 9 | * @var int |
|---|
| 10 | * |
|---|
| 11 | * TO DO: Rename |
|---|
| 12 | */ |
|---|
| 13 | public $page_crop = 512; |
|---|
| 14 | |
|---|
| 15 | var $admin_ui_processing; |
|---|
| 16 | var $site_icon; |
|---|
| 17 | var $admin_page_hook; |
|---|
| 18 | |
|---|
| 19 | public function __construct( $admin_ui_processing, $site_icon ) { |
|---|
| 20 | $this->admin_ui_processing = $admin_ui_processing; |
|---|
| 21 | $this->site_icon = $site_icon; |
|---|
| 22 | |
|---|
| 23 | // Add the favicon to the backend. |
|---|
| 24 | add_action( 'admin_head', 'wp_site_icon' ); |
|---|
| 25 | |
|---|
| 26 | add_action( 'admin_menu', array( $this, 'add_site_icon_page_to_menu' ) ); |
|---|
| 27 | add_action( 'admin_init', array( $this, 'add_upload_page_settings' ) ); |
|---|
| 28 | |
|---|
| 29 | add_action( 'admin_action_set_site_icon', array( $this, 'set_site_icon' ) ); |
|---|
| 30 | add_action( 'admin_action_remove_site_icon', array( $this, 'remove_site_icon' ) ); |
|---|
| 31 | } |
|---|
| 32 | |
|---|
| 33 | // To Do: nonce checking |
|---|
| 34 | public function site_icon_page_controller() { |
|---|
| 35 | $action = isset( $_GET['action'] ) ? $_GET['action'] : 'select-site-icon'; |
|---|
| 36 | |
|---|
| 37 | switch ( $action ) { |
|---|
| 38 | case 'select-site-icon': |
|---|
| 39 | $this->display_upload_page(); |
|---|
| 40 | break; |
|---|
| 41 | |
|---|
| 42 | case 'crop-site-icon': |
|---|
| 43 | // Handle image upload for the no Javascript version. |
|---|
| 44 | if ( isset ( $_GET['upload'] ) ) { |
|---|
| 45 | $attachment_id = $this->admin_ui_processing->upload_site_icon_image(); |
|---|
| 46 | } else { |
|---|
| 47 | // The Javascript upload skips the select and upload steps, providing the attachment ID. |
|---|
| 48 | $attachment_id = $_GET['file']; |
|---|
| 49 | } |
|---|
| 50 | |
|---|
| 51 | // Verify that the image is large enough. |
|---|
| 52 | $image_size = $this->admin_ui_processing->get_image_size_from_attachment( $attachment_id ); |
|---|
| 53 | |
|---|
| 54 | // TO DO: Move this to a method. |
|---|
| 55 | if ( $image_size[0] < $this->site_icon->min_size ) { |
|---|
| 56 | add_settings_error( 'site-icon', 'too-small', sprintf( __( 'The selected image is smaller than %upx in width.' ), $this->site_icon->min_size ) ); |
|---|
| 57 | $this->display_upload_page(); |
|---|
| 58 | } elseif ( $image_size[1] < $this->site_icon->min_size ) { |
|---|
| 59 | add_settings_error( 'site-icon', 'too-small', sprintf( __( 'The selected image is smaller than %upx in height.' ), $this->site_icon->min_size ) ); |
|---|
| 60 | $this->display_upload_page(); |
|---|
| 61 | } else { |
|---|
| 62 | // TO DO: Move this to a method. |
|---|
| 63 | // URL of the uploaded image. |
|---|
| 64 | $image_url = $this->admin_ui_processing->get_site_icon_image_url( $attachment_id ); |
|---|
| 65 | // Dimensions of the uploaded image adapted to the admin. |
|---|
| 66 | $max_height = $this->admin_ui_processing->calculate_height_of_image_for_cropping( $attachment_id, $this->page_crop ); |
|---|
| 67 | // Add the default crop values for the no JS version. |
|---|
| 68 | $default_crop = $this->admin_ui_processing->calculate_default_values_for_crop( $this->page_crop, $max_height ); |
|---|
| 69 | // Ratio for cropping |
|---|
| 70 | $crop_ratio = $image_size[0] / $this->page_crop; |
|---|
| 71 | |
|---|
| 72 | $this->display_crop_page( $attachment_id, $image_url, $this->page_crop, $max_height, $default_crop, $crop_ratio ); |
|---|
| 73 | } |
|---|
| 74 | break; |
|---|
| 75 | |
|---|
| 76 | default: |
|---|
| 77 | wp_safe_redirect( admin_url( 'options-general.php#site-icon' ) ); |
|---|
| 78 | exit; |
|---|
| 79 | } |
|---|
| 80 | } |
|---|
| 81 | |
|---|
| 82 | /** |
|---|
| 83 | * Adds the Site Icon Page to the admin menu. |
|---|
| 84 | * |
|---|
| 85 | * The `parent_slug` argument in `add_menu_page()` is set to `null`, so that no link is added in the admin interface. |
|---|
| 86 | * |
|---|
| 87 | * @since 4.3.0 |
|---|
| 88 | */ |
|---|
| 89 | public function add_site_icon_page_to_menu() { |
|---|
| 90 | $hook = add_submenu_page( null, __( 'Site Icon' ), __( 'Site Icon' ), 'manage_options', 'site-icon', array( $this, 'site_icon_page_controller' ) ); |
|---|
| 91 | |
|---|
| 92 | add_action( "admin_print_scripts-$hook", array( $this, 'enqueue_scripts' ) ); |
|---|
| 93 | } |
|---|
| 94 | |
|---|
| 95 | /** |
|---|
| 96 | * Register a settings section for uploading a Site Icon image. |
|---|
| 97 | * |
|---|
| 98 | * @since 4.3.0 |
|---|
| 99 | */ |
|---|
| 100 | public function add_upload_page_settings() { |
|---|
| 101 | add_settings_section( 'site-icon-upload', false, false, 'site-icon-upload' ); |
|---|
| 102 | add_settings_field( 'site-icon-upload', __( 'Upload Image' ), array( $this, 'display_upload_page_image_selection' ), 'site-icon-upload', 'site-icon-upload', array( |
|---|
| 103 | 'label_for' => 'site-icon-upload', |
|---|
| 104 | ) ); |
|---|
| 105 | } |
|---|
| 106 | |
|---|
| 107 | /** |
|---|
| 108 | * Add scripts to admin settings pages. |
|---|
| 109 | * |
|---|
| 110 | * @since 4.3.0 |
|---|
| 111 | */ |
|---|
| 112 | public function enqueue_scripts() { |
|---|
| 113 | wp_enqueue_style( 'jcrop' ); |
|---|
| 114 | wp_enqueue_script( 'site-icon-crop' ); |
|---|
| 115 | } |
|---|
| 116 | |
|---|
| 117 | /** |
|---|
| 118 | * Display the admin page for uploading a Site Icon image. |
|---|
| 119 | * |
|---|
| 120 | * This screen is only visible when Javascript is deactivated. |
|---|
| 121 | * |
|---|
| 122 | * @since 4.3.0 |
|---|
| 123 | */ |
|---|
| 124 | public function display_upload_page() { |
|---|
| 125 | ?> |
|---|
| 126 | <div class="wrap"> |
|---|
| 127 | <h2><?php _e( 'Add Site Icon' ); ?></h2> |
|---|
| 128 | <?php settings_errors( 'site-icon' ); ?> |
|---|
| 129 | <?php do_settings_sections( 'site-icon-upload' ); ?> |
|---|
| 130 | </div> |
|---|
| 131 | <?php |
|---|
| 132 | } |
|---|
| 133 | |
|---|
| 134 | /** |
|---|
| 135 | * Settings field for file upload. |
|---|
| 136 | * |
|---|
| 137 | * @since 4.3.0 |
|---|
| 138 | */ |
|---|
| 139 | public function display_upload_page_image_selection() { |
|---|
| 140 | // Render modal for uploading via Javascript. |
|---|
| 141 | // TO DO: Script enqueuing should be done in a single method. |
|---|
| 142 | wp_enqueue_media(); |
|---|
| 143 | wp_enqueue_script( 'site-icon' ); |
|---|
| 144 | wp_dequeue_script( 'site-icon-crop' ); |
|---|
| 145 | |
|---|
| 146 | $update_url = esc_url( add_query_arg( array( |
|---|
| 147 | 'page' => 'site-icon', |
|---|
| 148 | 'action' => 'crop-site-icon', |
|---|
| 149 | ), wp_nonce_url( admin_url( 'options-general.php' ), 'crop-site-icon' ) ) ); |
|---|
| 150 | ?> |
|---|
| 151 | <p class="hide-if-no-js"> |
|---|
| 152 | <label class="screen-reader-text" for="choose-from-library-link"><?php _e( 'Choose an image from your media library:' ); ?></label> |
|---|
| 153 | <?php |
|---|
| 154 | printf( '<button type="button" id="choose-from-library-link" class="button" data-update-link="%$1s" data-choose="%$2s" data-update="%$3s">%$4s</button>', |
|---|
| 155 | esc_attr( $update_url ), |
|---|
| 156 | esc_attr__( 'Choose a Site Icon' ), |
|---|
| 157 | esc_attr__( 'Set as Site Icon' ), |
|---|
| 158 | __( 'Choose Image' ) |
|---|
| 159 | ); |
|---|
| 160 | ?> |
|---|
| 161 | </p> |
|---|
| 162 | |
|---|
| 163 | <?php // Upload form for when Javascript is deactivated ?> |
|---|
| 164 | <form class="hide-if-js" action="<?php echo esc_url( admin_url( 'options-general.php?page=site-icon&action=crop-site-icon&upload' ) ); ?>" method="post" enctype="multipart/form-data"> |
|---|
| 165 | <input name="action" value="crop_site_icon" type="hidden" /> |
|---|
| 166 | <input name="site-icon" type="file" /> |
|---|
| 167 | <input name="submit" value="<?php esc_attr_e( 'Upload Image' ); ?>" type="submit" class="button button-primary" /> |
|---|
| 168 | <p class="description"> |
|---|
| 169 | <?php printf( __( 'The image is recommended to be a square image of at least %spx in both width and height.' ), "<strong>" . absint( $this->site_icon->min_size ) . '</strong>' ); ?> |
|---|
| 170 | </p> |
|---|
| 171 | <?php wp_nonce_field( 'crop-site-icon' ); ?> |
|---|
| 172 | </form> |
|---|
| 173 | <?php |
|---|
| 174 | } |
|---|
| 175 | |
|---|
| 176 | public function display_crop_page( $attachment_id, $image_url, $resized_image_width, $resized_image_height, $default_crop, $crop_ratio ) { |
|---|
| 177 | check_admin_referer( 'crop-site-icon' ); |
|---|
| 178 | |
|---|
| 179 | // TO DO: Script enqueuing should be done in a single method. |
|---|
| 180 | $image_size = $this->admin_ui_processing->get_attachment_image_size( $attachment_id ); |
|---|
| 181 | wp_localize_script( 'site-icon-crop', 'wpSiteIconCropData', $this->admin_ui_processing->calculate_default_values_for_javascript_cropper( $crop_ratio, $this->page_crop, $resized_image_width, $resized_image_height, $image_size[0], $image_size[1] ) ); |
|---|
| 182 | ?> |
|---|
| 183 | <div class="wrap"> |
|---|
| 184 | <h2 class="site-icon-title"><?php _e( 'Site Icon' ); ?></h2> |
|---|
| 185 | <?php settings_errors( 'site-icon' ); ?> |
|---|
| 186 | |
|---|
| 187 | <div class="site-icon-crop-shell"> |
|---|
| 188 | <form action="options-general.php" method="post" enctype="multipart/form-data"> |
|---|
| 189 | <p class="hide-if-no-js description"><?php _e('Choose the part of the image you want to use as your site icon.'); ?></p> |
|---|
| 190 | <p class="hide-if-js description"><strong><?php _e( 'You need Javascript to choose a part of the image.'); ?></strong></p> |
|---|
| 191 | <?php |
|---|
| 192 | // Image which is used to select the right cropping. |
|---|
| 193 | // This image needs to be resized to allow for easy cropping. |
|---|
| 194 | printf( '<img src="%1$s" id="crop-image" class="site-icon-crop-image" width="%2$s" height="%3$s" alt="%4$s" />', |
|---|
| 195 | esc_url( $image_url ), |
|---|
| 196 | absint( $resized_image_width ), |
|---|
| 197 | absint( $resized_image_height ), |
|---|
| 198 | esc_attr__( 'Image to be cropped' ) |
|---|
| 199 | ); |
|---|
| 200 | |
|---|
| 201 | // Site icon preview in browser bar and on mobile. |
|---|
| 202 | ?> |
|---|
| 203 | <div class="site-icon-crop-preview-shell hide-if-no-js"> |
|---|
| 204 | <h3><?php _e( 'Preview' ); ?></h3> |
|---|
| 205 | <strong><?php _e( 'As your favicon' ); ?></strong> |
|---|
| 206 | <div class="site-icon-crop-favicon-preview-shell"> |
|---|
| 207 | <img src="images/browser.png" class="site-icon-browser-preview" width="182" height="" alt="<?php esc_attr_e( 'Browser Chrome' ); ?>"/> |
|---|
| 208 | <div class="site-icon-crop-preview-favicon"> |
|---|
| 209 | <img src="<?php echo esc_url( $image_url ); ?>" id="preview-favicon" alt="<?php esc_attr_e( 'Preview Favicon' ); ?>"/> |
|---|
| 210 | </div> |
|---|
| 211 | <span class="site-icon-browser-title"><?php bloginfo( 'name' ); ?></span> |
|---|
| 212 | </div> |
|---|
| 213 | <strong><?php _e( 'As a mobile icon' ); ?></strong> |
|---|
| 214 | <div class="site-icon-crop-preview-homeicon"> |
|---|
| 215 | <img src="<?php echo esc_url( $image_url ); ?>" id="preview-homeicon" alt="<?php esc_attr_e( 'Preview Home Icon' ); ?>"/> |
|---|
| 216 | </div> |
|---|
| 217 | </div> |
|---|
| 218 | |
|---|
| 219 | <?php // Default crop values for no JS fallback. ?> |
|---|
| 220 | <input type="hidden" id="crop-x" name="crop-x" value="<?php echo absint( $default_crop['crop_x'] ); ?>" /> |
|---|
| 221 | <input type="hidden" id="crop-y" name="crop-y" value="<?php echo absint( $default_crop['crop_y'] ); ?>" /> |
|---|
| 222 | <input type="hidden" id="crop-width" name="crop-w" value="<?php echo absint( $default_crop['crop_size'] ); ?>" /> |
|---|
| 223 | <input type="hidden" id="crop-height" name="crop-h" value="<?php echo absint( $default_crop['crop_size'] ); ?>" /> |
|---|
| 224 | |
|---|
| 225 | <input type="hidden" name="action" value="set_site_icon" /> |
|---|
| 226 | <input type="hidden" name="attachment_id" value="<?php echo esc_attr( $attachment_id ); ?>" /> |
|---|
| 227 | |
|---|
| 228 | <input type="hidden" name="crop_ratio" value="<?php echo esc_attr( $crop_ratio ); ?>" /> |
|---|
| 229 | <?php if ( empty( $_POST ) && isset( $_GET['file'] ) ) : ?> |
|---|
| 230 | <input type="hidden" name="create-new-attachment" value="true" /> |
|---|
| 231 | <?php endif; ?> |
|---|
| 232 | <?php wp_nonce_field( 'set-site-icon' ); ?> |
|---|
| 233 | |
|---|
| 234 | <p class="submit"> |
|---|
| 235 | <?php submit_button( __( 'Crop and Publish' ), 'primary hide-if-no-js', 'submit', false ); ?> |
|---|
| 236 | <?php submit_button( __( 'Publish' ), 'primary hide-if-js', 'submit', false ); ?> |
|---|
| 237 | <a class="button secondary" href="options-general.php"><?php _e( 'Cancel' ); ?></a> |
|---|
| 238 | </p> |
|---|
| 239 | </form> |
|---|
| 240 | </div> |
|---|
| 241 | </div> |
|---|
| 242 | <?php |
|---|
| 243 | } |
|---|
| 244 | |
|---|
| 245 | /** |
|---|
| 246 | * Saves a new Site Icon. |
|---|
| 247 | * |
|---|
| 248 | * TO DO: Split this apart, and move code to smaller methods in `WP_Site_Icon_Admin_Processing`. |
|---|
| 249 | * |
|---|
| 250 | * @since 4.3.0 |
|---|
| 251 | */ |
|---|
| 252 | public function set_site_icon() { |
|---|
| 253 | check_admin_referer( 'set-site-icon' ); |
|---|
| 254 | |
|---|
| 255 | // Delete any existing site icon images. |
|---|
| 256 | $this->admin_ui_processing->delete_site_icon(); |
|---|
| 257 | |
|---|
| 258 | $attachment_id = absint( $_POST['attachment_id'] ); |
|---|
| 259 | |
|---|
| 260 | // TODO |
|---|
| 261 | if ( empty( $_POST['skip-cropping'] ) ) { |
|---|
| 262 | $crop_ratio = (float) $_POST['crop_ratio']; |
|---|
| 263 | $crop_data = $this->admin_ui_processing->convert_coordinates_from_resized_to_full( $_POST['crop-x'], $_POST['crop-y'], $_POST['crop-w'], $_POST['crop-h'], $crop_ratio ); |
|---|
| 264 | $cropped = wp_crop_image( $attachment_id, $crop_data['crop_x'], $crop_data['crop_y'], $crop_data['crop_width'], $crop_data['crop_height'], $this->site_icon->min_size, $this->site_icon->min_size ); |
|---|
| 265 | } elseif ( ! empty( $_POST['create-new-attachment'] ) ) { |
|---|
| 266 | $cropped = _copy_image_file( $attachment_id ); |
|---|
| 267 | } else { |
|---|
| 268 | $cropped = get_attached_file( $attachment_id ); |
|---|
| 269 | } |
|---|
| 270 | |
|---|
| 271 | if ( ! $cropped || is_wp_error( $cropped ) ) { |
|---|
| 272 | wp_die( __( 'Image could not be processed. Please go back and try again.' ), __( 'Image Processing Error' ) ); |
|---|
| 273 | } |
|---|
| 274 | |
|---|
| 275 | $object = $this->admin_ui_processing->create_attachment_object( $cropped, $attachment_id ); |
|---|
| 276 | |
|---|
| 277 | if ( ! empty( $_POST['create-new-attachment'] ) ) { |
|---|
| 278 | unset( $object['ID'] ); |
|---|
| 279 | } |
|---|
| 280 | |
|---|
| 281 | // Update the attachment |
|---|
| 282 | add_filter( 'intermediate_image_sizes_advanced', array( $this->site_icon, 'additional_sizes' ) ); |
|---|
| 283 | $attachment_id = $this->admin_ui_processing->insert_attachment( $object, $cropped ); |
|---|
| 284 | remove_filter( 'intermediate_image_sizes_advanced', array( $this->site_icon, 'additional_sizes' ) ); |
|---|
| 285 | |
|---|
| 286 | // Save the site_icon data into option |
|---|
| 287 | update_option( 'site_icon', $attachment_id ); |
|---|
| 288 | |
|---|
| 289 | add_settings_error( 'site-icon', 'icon-updated', __( 'Site Icon updated.' ), 'updated' ); |
|---|
| 290 | } |
|---|
| 291 | |
|---|
| 292 | /** |
|---|
| 293 | * Removes site icon. |
|---|
| 294 | * |
|---|
| 295 | * @since 4.3.0 |
|---|
| 296 | */ |
|---|
| 297 | public function remove_site_icon() { |
|---|
| 298 | check_admin_referer( 'remove-site-icon' ); |
|---|
| 299 | |
|---|
| 300 | // TO DO: Check return value to display success message. |
|---|
| 301 | $this->admin_ui_processing->delete_site_icon(); |
|---|
| 302 | |
|---|
| 303 | add_settings_error( 'site-icon', 'icon-removed', __( 'Site Icon removed.' ), 'updated' ); |
|---|
| 304 | } |
|---|
| 305 | |
|---|
| 306 | } |
|---|
| 307 | |
|---|
| 308 | $site_icon_admin = new WP_Site_Icon_Admin_UI( new WP_Site_Icon_Admin_Processing(), WP_Site_Icon::get_instance() ); |
|---|