From 35feae5c75169ce83620091e9849ee0fdec8bd9e Mon Sep 17 00:00:00 2001 From: Aaron Jorbin Date: Mon, 12 Feb 2024 21:55:44 +0000 Subject: [PATCH] General: Add an option to configure the site icon in general settings. This restores the site icon setting to its original home on the settings page where it lives with the title and tagline. The base for this code was originally added in [32994] and then removed in [33329]. The majority of the modification to that version are to remove the no-js pieces and make the workflow completely inline rather than putting the cropping on a separate page. Additionally, since image crops rely on the ability to upload an image, this setting is gated by the `upload_files` capability. Follow-up to: [32994], [33329]. Props jorbin, audrasjb, mukesh27, joedolson, afercia, kebbet, swissspidy, obenland, jameskoster, kjellr, andraganescu, stacimc, mikeschroder, h71, krupajnanda, huzaifaalmesbah. Fixes #54370. See #16434. git-svn-id: https://develop.svn.wordpress.org/trunk@57602 602fd350-edb4-49c9-b593-d223f7449a82 --- Gruntfile.js | 1 + src/js/_enqueues/admin/site-icon.js | 138 ++++++++++++++++++++++++++++ src/wp-admin/css/forms.css | 36 ++++++++ src/wp-admin/css/site-icon.css | 18 ++++ src/wp-admin/options-general.php | 81 +++++++++++++++- src/wp-admin/options.php | 1 + src/wp-includes/css/media-views.css | 9 ++ src/wp-includes/script-loader.php | 2 + 8 files changed, 285 insertions(+), 1 deletion(-) create mode 100644 src/js/_enqueues/admin/site-icon.js diff --git a/Gruntfile.js b/Gruntfile.js index 38904c6dac170..7d6981248f199 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -332,6 +332,7 @@ module.exports = function(grunt) { [ WORKING_DIR + 'wp-admin/js/tags-suggest.js' ]: [ './src/js/_enqueues/admin/tags-suggest.js' ], [ WORKING_DIR + 'wp-admin/js/tags.js' ]: [ './src/js/_enqueues/admin/tags.js' ], [ WORKING_DIR + 'wp-admin/js/site-health.js' ]: [ './src/js/_enqueues/admin/site-health.js' ], + [ WORKING_DIR + 'wp-admin/js/site-icon.js' ]: [ './src/js/_enqueues/admin/site-icon.js' ], [ WORKING_DIR + 'wp-admin/js/privacy-tools.js' ]: [ './src/js/_enqueues/admin/privacy-tools.js' ], [ WORKING_DIR + 'wp-admin/js/theme-plugin-editor.js' ]: [ './src/js/_enqueues/wp/theme-plugin-editor.js' ], [ WORKING_DIR + 'wp-admin/js/theme.js' ]: [ './src/js/_enqueues/wp/theme.js' ], diff --git a/src/js/_enqueues/admin/site-icon.js b/src/js/_enqueues/admin/site-icon.js new file mode 100644 index 0000000000000..5b4bc28a2044f --- /dev/null +++ b/src/js/_enqueues/admin/site-icon.js @@ -0,0 +1,138 @@ +(function($) { + var frame; + + function calculateImageSelectOptions ( attachment ) { + var realWidth = attachment.get( 'width' ), + realHeight = attachment.get( 'height' ), + xInit = 512, + yInit = 512, + ratio = xInit / yInit, + xImg = xInit, + yImg = yInit, + x1, y1, imgSelectOptions; + + if ( realWidth / realHeight > ratio ) { + yInit = realHeight; + xInit = yInit * ratio; + } else { + xInit = realWidth; + yInit = xInit / ratio; + } + + x1 = ( realWidth - xInit ) / 2; + y1 = ( realHeight - yInit ) / 2; + + imgSelectOptions = { + aspectRatio: xInit + ':' + yInit, + handles: true, + keys: true, + instance: true, + persistent: true, + imageWidth: realWidth, + imageHeight: realHeight, + minWidth: xImg > xInit ? xInit : xImg, + minHeight: yImg > yInit ? yInit : yImg, + x1: x1, + y1: y1, + x2: xInit + x1, + y2: yInit + y1 + }; + + return imgSelectOptions; + } + + $( function() { + // Build the choose from library frame. + $( '#choose-from-library-link' ).on( 'click', function() { + var $el = $(this); + + // Create the media frame. + frame = wp.media({ + button: { + // Set the text of the button. + text: $el.data('update'), + // Don't close, we might need to crop. + close: false + }, + states: [ + new wp.media.controller.Library({ + title: $el.data( 'choose' ), + library: wp.media.query({ type: 'image' }), + date: false, + suggestedWidth: $el.data( 'size' ), + suggestedHeight: $el.data( 'size' ) + }), + new wp.media.controller.SiteIconCropper({ + control: { + params: { + width: $el.data( 'size' ), + height: $el.data( 'size' ) + } + }, + imgSelectOptions: calculateImageSelectOptions + }) + ] + }); + + frame.on( 'cropped', function( attachment) { + $( '#site_icon_hidden_field' ).val(attachment.id); + switchToUpdate(attachment.url); + frame.close(); + // Start over with a frame that is so fresh and so clean clean. + frame = null; + }); + + // When an image is selected, run a callback. + frame.on( 'select', function() { + // Grab the selected attachment. + var attachment = frame.state().get('selection').first(); + + if ( attachment.attributes.height === $el.data('size') && $el.data('size') === attachment.attributes.width ) { + // Set the value of the hidden input to the attachment id. + $( '#site_icon_hidden_field').val(attachment.id); + switchToUpdate(attachment.attributes.url); + frame.close(); + } else { + frame.setState( 'cropper' ); + } + }); + + frame.open(); + }); + }); + + function switchToUpdate( url ){ + // Set site-icon-img src to the url and remove the hidden class. + $( '#site-icon-preview').find('img').not('.browser-preview').each( function(i, img ){ + $(img).attr('src', url ); + }); + $( '#site-icon-preview' ).removeClass( 'hidden' ); + // Remove hidden class from remove. + $( '#js-remove-site-icon' ).removeClass( 'hidden' ); + // If the button is not in the update state, swap the classes. + if( $( '#choose-from-library-link' ).attr( 'data-state' ) !== '1' ){ + var classes = $( '#choose-from-library-link' ).attr( 'class' ); + $( '#choose-from-library-link' ).attr( 'class', $( '#choose-from-library-link' ).attr('data-alt-classes') ); + $( '#choose-from-library-link' ).attr( 'data-alt-classes', classes ); + $( '#choose-from-library-link' ).attr( 'data-state', '1' ); + } + + // swap the text of the button + $( '#choose-from-library-link' ).text( $( '#choose-from-library-link' ).attr( 'data-update-text' ) ); + } + + $( '#js-remove-site-icon' ).on( 'click', function() { + $( '#site_icon_hidden_field' ).val( 'false' ); + $( '#site-icon-preview' ).toggleClass( 'hidden' ); + $( this ).toggleClass( 'hidden' ); + + var classes = $( '#choose-from-library-link' ).attr( 'class' ); + $( '#choose-from-library-link' ).attr( 'class', $( '#choose-from-library-link' ).attr( 'data-alt-classes' ) ); + $( '#choose-from-library-link' ).attr( 'data-alt-classes', classes ); + + // Swap the text of the button. + $( '#choose-from-library-link' ).text( $( '#choose-from-library-link' ).attr( 'data-choose-text' ) ); + // Set the state of the button so it can be changed on new icon. + $( '#choose-from-library-link' ).attr( 'data-state', ''); + }); +}(jQuery)); diff --git a/src/wp-admin/css/forms.css b/src/wp-admin/css/forms.css index e6610cac47ea9..db76d6cb05e7a 100644 --- a/src/wp-admin/css/forms.css +++ b/src/wp-admin/css/forms.css @@ -789,6 +789,42 @@ ul#add-to-blog-users { outline: 2px solid transparent; } +.button-add-site-icon{ + width: 100%; + cursor: pointer; + text-align: center; + border: 1px dashed #c3c4c7; + box-sizing: border-box; + padding: 9px 0; + line-height: 1.6; + max-width: 270px; +} + +.button-add-site-icon:focus, +.button-add-site-icon:hover{ + background: white; +} + +.site-icon-section .favicon-preview{ + float: left; +} +.site-icon-section .app-icon-preview{ + float: left; + margin: 0 20px; +} + +.site-icon-section .site-icon-preview img{ + max-width: 100%; +} + +.button-ad-site-icon:focus{ + background-color: #fff; + border-color: #3582c4; + border-style: solid; + box-shadow: 0 0 0 1px #3582c4; + outline: 2px solid transparent; +} + /*------------------------------------------------------------------------------ 15.0 - Comments Screen ------------------------------------------------------------------------------*/ diff --git a/src/wp-admin/css/site-icon.css b/src/wp-admin/css/site-icon.css index eae9a576357a8..7c6ce8663e597 100644 --- a/src/wp-admin/css/site-icon.css +++ b/src/wp-admin/css/site-icon.css @@ -7,6 +7,7 @@ overflow: hidden; position: relative; max-width: 180px; + float: left; } .site-icon-preview .favicon, @@ -52,3 +53,20 @@ .customize-control-site_icon .app-icon-preview { margin-top: 9px; } + +.site-icon-section button.reset { + color: #b32d2e; + text-decoration: none; + border-color: transparent; + box-shadow: none; + background: transparent; + margin: 0 10px; +} + +.site-icon-section button.reset:focus, +.site-icon-section button.reset:hover { + background: #b32d2e; + color: #fff; + border-color: #b32d2e; + box-shadow: 0 0 0 1px #b32d2e; +} diff --git a/src/wp-admin/options-general.php b/src/wp-admin/options-general.php index 490a138580c5f..a516757327a8d 100644 --- a/src/wp-admin/options-general.php +++ b/src/wp-admin/options-general.php @@ -97,7 +97,86 @@

- + + + + +
+
+ +
+ Preview as a browser icon +
+ +
+ Preview as an app icon +
+ +

+ + +

+ +

+ +

+

+ 512 × 512' ); + ?> +

+ + + + + array( 'blogname', 'blogdescription', + 'site_icon', 'gmt_offset', 'date_format', 'time_format', diff --git a/src/wp-includes/css/media-views.css b/src/wp-includes/css/media-views.css index c681f6df78d77..ab392ef890b36 100644 --- a/src/wp-includes/css/media-views.css +++ b/src/wp-includes/css/media-views.css @@ -849,6 +849,7 @@ height: 100%; } +.options-general-php .crop-content.site-icon, .wp-customizer:not(.mobile) .media-frame-content .crop-content.site-icon { margin-right: 300px; } @@ -2560,6 +2561,10 @@ width: 230px; } + .options-general-php .crop-content.site-icon { + margin-right: 262px; + } + .attachments-browser .attachments, .attachments-browser .uploader-inline, .attachments-browser .media-toolbar, @@ -2827,6 +2832,10 @@ position: fixed; } + .options-general-php .crop-content.site-icon { + margin-right: 0; + } + .media-sidebar { z-index: 1900; max-width: 70%; diff --git a/src/wp-includes/script-loader.php b/src/wp-includes/script-loader.php index 932fcfc06c6c0..f41da6eff3a5c 100644 --- a/src/wp-includes/script-loader.php +++ b/src/wp-includes/script-loader.php @@ -849,6 +849,8 @@ function wp_default_scripts( $scripts ) { $scripts->add( 'wp-lists', "/wp-includes/js/wp-lists$suffix.js", array( 'wp-ajax-response', 'jquery-color' ), false, 1 ); + $scripts->add( 'site-icon', '/wp-admin/js/site-icon.js', array( 'jquery', 'jcrop' ), false, 1 ); + // WordPress no longer uses or bundles Prototype or script.aculo.us. These are now pulled from an external source. $scripts->add( 'prototype', 'https://ajax.googleapis.com/ajax/libs/prototype/1.7.1.0/prototype.js', array(), '1.7.1' ); $scripts->add( 'scriptaculous-root', 'https://ajax.googleapis.com/ajax/libs/scriptaculous/1.9.0/scriptaculous.js', array( 'prototype' ), '1.9.0' );