WordPress.org

Make WordPress Core

Ticket #16434: 16434.15.diff

File 16434.15.diff, 19.2 KB (added by obenland, 3 years ago)
  • src/wp-admin/admin-ajax.php

     
    6262        'send-attachment-to-editor', 'save-attachment-order', 'heartbeat', 'get-revision-diffs',
    6363        'save-user-color-scheme', 'update-widget', 'query-themes', 'parse-embed', 'set-attachment-thumbnail',
    6464        'parse-media-shortcode', 'destroy-sessions', 'install-plugin', 'update-plugin', 'press-this-save-post',
    65         'press-this-add-category',
     65        'press-this-add-category', 'crop-image',
    6666);
    6767
    6868// Deprecated
  • src/wp-admin/css/customize-controls.css

     
    771771.customize-control-upload .current,
    772772.customize-control-image .current,
    773773.customize-control-background .current,
     774.customize-control-cropped_image .current,
     775.customize-control-site_icon .current,
    774776.customize-control-header .current {
    775777        margin-bottom: 8px;
    776778}
     
    806808.customize-control-background .remove-button,
    807809.customize-control-background .default-button,
    808810.customize-control-background .upload-button,
     811.customize-control-cropped_image .remove-button,
     812.customize-control-cropped_image .default-button,
     813.customize-control-cropped_image .upload-button,
     814.customize-control-site_icon .remove-button,
     815.customize-control-site_icon .default-button,
     816.customize-control-site_icon .upload-button,
    809817.customize-control-header button.new,
    810818.customize-control-header button.remove {
    811819        white-space: normal;
     
    817825.customize-control-upload .current .container,
    818826.customize-control-image .current .container,
    819827.customize-control-background .current .container,
     828.customize-control-cropped_image .current .container,
     829.customize-control-site_icon .current .container,
    820830.customize-control-header .current .container {
    821831        overflow: hidden;
    822832        -webkit-border-radius: 2px;
     
    828838.customize-control-media .current .container,
    829839.customize-control-upload .current .container,
    830840.customize-control-background .current .container,
     841.customize-control-cropped_image .current .container,
     842.customize-control-site_icon .current .container,
    831843.customize-control-image .current .container {
    832844        min-height: 40px;
    833845}
     
    836848.customize-control-upload .placeholder,
    837849.customize-control-image .placeholder,
    838850.customize-control-background .placeholder,
     851.customize-control-cropped_image .placeholder,
     852.customize-control-site_icon .placeholder,
    839853.customize-control-header .placeholder {
    840854        width: 100%;
    841855        position: relative;
     
    847861.customize-control-upload .inner,
    848862.customize-control-image .inner,
    849863.customize-control-background .inner,
     864.customize-control-cropped_image .inner,
     865.customize-control-site_icon .inner,
    850866.customize-control-header .inner {
    851867        display: none;
    852868        position: absolute;
     
    860876.customize-control-media .inner,
    861877.customize-control-upload .inner,
    862878.customize-control-background .inner,
     879.customize-control-cropped_image .inner,
     880.customize-control-site_icon .inner,
    863881.customize-control-image .inner {
    864882        display: block;
    865883        min-height: 40px;
     
    869887.customize-control-upload .inner,
    870888.customize-control-image .inner,
    871889.customize-control-background .inner,
     890.customize-control-cropped_image .inner,
     891.customize-control-site_icon .inner,
    872892.customize-control-header .inner,
    873893.customize-control-header .inner .dashicons {
    874894        line-height: 20px;
     
    972992.customize-control-upload .actions,
    973993.customize-control-image .actions,
    974994.customize-control-background .actions,
     995.customize-control-cropped_image .actions,
     996.customize-control-site_icon .actions,
    975997.customize-control-header .actions {
    976998        margin-bottom: 32px;
    977999}
     
    9901012.customize-control-upload img,
    9911013.customize-control-image img,
    9921014.customize-control-background img,
     1015.customize-control-cropped_image img,
     1016.customize-control-site_icon img,
    9931017.customize-control-header img {
    9941018        width: 100%;
    9951019        -webkit-border-radius: 2px;
     
    10041028.customize-control-image .default-button,
    10051029.customize-control-background .remove-button,
    10061030.customize-control-background .default-button,
     1031.customize-control-cropped_image .remove-button,
     1032.customize-control-cropped_image .default-button,
     1033.customize-control-site_icon .remove-button,
     1034.customize-control-site_icon .default-button,
    10071035.customize-control-header .remove {
    10081036        float: left;
    10091037        margin-right: 3px;
     
    10131041.customize-control-upload .upload-button,
    10141042.customize-control-image .upload-button,
    10151043.customize-control-background .upload-button,
     1044.customize-control-cropped_image .upload-button,
     1045.customize-control-site_icon .upload-button,
    10161046.customize-control-header .new {
    10171047        float: right;
    10181048}
  • src/wp-admin/includes/ajax-actions.php

     
    30523052
    30533053        $GLOBALS['wp_press_this']->add_category();
    30543054}
     3055
     3056/**
     3057 * AJAX handler for cropping an image.
     3058 *
     3059 * @since 4.3.0
     3060 *
     3061 * @global WP_Site_Icon $wp_site_icon
     3062 */
     3063function wp_ajax_crop_image() {
     3064        $attachment_id = absint( $_POST['id'] );
     3065
     3066        check_ajax_referer( 'image_editor-' . $attachment_id, 'nonce' );
     3067        if ( ! current_user_can( 'customize' ) ) {
     3068                wp_send_json_error();
     3069        }
     3070
     3071        $context = $_POST['context'];
     3072        $data    = array_map( 'absint', $_POST['cropDetails'] );
     3073        $cropped = wp_crop_image( $attachment_id, $data['x1'], $data['y1'], $data['width'], $data['height'], $data['dst_width'], $data['dst_height'] );
     3074
     3075        if ( ! $cropped || is_wp_error( $cropped ) ) {
     3076                wp_send_json_error( array( 'message' => __( 'Image could not be processed. Please go back and try again.' ) ) );
     3077        }
     3078
     3079        switch ( $context ) {
     3080                case 'site_icon':
     3081                        require_once ABSPATH . '/wp-admin/includes/class-wp-site-icon.php';
     3082                        global $wp_site_icon;
     3083
     3084                        /** This filter is documented in wp-admin/custom-header.php */
     3085                        $cropped = apply_filters( 'wp_create_file_in_uploads', $cropped, $attachment_id ); // For replication.
     3086                        $object  = $wp_site_icon->create_attachment_object( $cropped, $attachment_id );
     3087                        unset( $object['ID'] );
     3088
     3089                        // Update the attachment.
     3090                        add_filter( 'intermediate_image_sizes_advanced', array( $wp_site_icon, 'additional_sizes' ) );
     3091                        $attachment_id = $wp_site_icon->insert_attachment( $object, $cropped );
     3092                        remove_filter( 'intermediate_image_sizes_advanced', array( $wp_site_icon, 'additional_sizes' ) );
     3093                        break;
     3094
     3095                default:
     3096
     3097                        /**
     3098                         * Filters the attachment id for a cropped image.
     3099                         *
     3100                         * @since 4.3.0
     3101                         *
     3102                         * @param int    $attachment_id The ID of the cropped image.
     3103                         * @param string $context       The feature requesting the cropped image.
     3104                         */
     3105                        $attachment_id = apply_filters( 'wp_ajax_cropped_attachment_id', 0, $context );
     3106        }
     3107
     3108        if ( ! $attachment_id ) {
     3109                wp_send_json_error();
     3110        }
     3111
     3112        wp_send_json_success( wp_prepare_attachment_for_js( $attachment_id ) );
     3113}
     3114 No newline at end of file
  • src/wp-admin/js/customize-controls.js

     
    18361836        });
    18371837
    18381838        /**
     1839         * A control for selecting and cropping an image.
     1840         *
     1841         * @class
     1842         * @augments wp.customize.MediaControl
     1843         * @augments wp.customize.Control
     1844         * @augments wp.customize.Class
     1845         */
     1846        api.CroppedImageControl = api.MediaControl.extend({
     1847                /**
     1848                 * Open the media modal to the library state.
     1849                 */
     1850                openFrame: function( event ) {
     1851                        if ( api.utils.isKeydownButNotEnterEvent( event ) ) {
     1852                                return;
     1853                        }
     1854
     1855                        if ( this.frame ) {
     1856                                this.frame.setState( 'library' );
     1857                        }
     1858
     1859                        api.MediaControl.prototype.openFrame.call( this, event );
     1860                },
     1861
     1862                /**
     1863                 * Create a media modal select frame, and store it so the instance can be reused when needed.
     1864                 */
     1865                initFrame: function() {
     1866                        var l10n = _wpMediaViewsL10n;
     1867
     1868                        this.frame = wp.media({
     1869                                button: {
     1870                                        text: l10n.selectAndCrop,
     1871                                        close: false
     1872                                },
     1873                                states: [
     1874                                        new wp.media.controller.Library({
     1875                                                title: this.params.button_labels.frame_title,
     1876                                                library: wp.media.query({ type: 'image' }),
     1877                                                multiple: false,
     1878                                                date: false,
     1879                                                priority: 20,
     1880                                                suggestedWidth: this.params.width,
     1881                                                suggestedHeight: this.params.height
     1882                                        }),
     1883                                        new wp.media.controller.customizeImageCropper({
     1884                                                imgSelectOptions: this.calculateImageSelectOptions,
     1885                                                control: this
     1886                                        })
     1887                                ]
     1888                        });
     1889
     1890                        this.frame.on( 'select', this.onSelect, this );
     1891                        this.frame.on( 'cropped', this.onCropped, this );
     1892                        this.frame.on( 'skippedcrop', this.onSkippedCrop, this );
     1893                },
     1894
     1895                /**
     1896                 * After an image is selected in the media modal,
     1897                 * switch to the cropper state.
     1898                 */
     1899                onSelect: function() {
     1900                        this.frame.setState( 'cropper' );
     1901                },
     1902
     1903                /**
     1904                 * After the image has been cropped, apply the cropped image data to the setting.
     1905                 *
     1906                 * @param {object} croppedImage Cropped attachment data.
     1907                 */
     1908                onCropped: function( croppedImage ) {
     1909                        this.setImageFromAttachment( croppedImage );
     1910                },
     1911
     1912                /**
     1913                 * Returns a set of options, computed from the attached image data and
     1914                 * control-specific data, to be fed to the imgAreaSelect plugin in
     1915                 * wp.media.view.Cropper.
     1916                 *
     1917                 * @param {wp.media.model.Attachment} attachment
     1918                 * @param {wp.media.controller.Cropper} controller
     1919                 * @returns {Object} Options
     1920                 */
     1921                calculateImageSelectOptions: function( attachment, controller ) {
     1922                        var control = controller.get( 'control' ),
     1923                                xInit = parseInt( control.params.width, 10 ),
     1924                                yInit = parseInt( control.params.height, 10 ),
     1925                                flexWidth  = !! parseInt( control.params.flex_width, 10 ),
     1926                                flexHeight = !! parseInt( control.params.flex_height, 10 ),
     1927                                realWidth  = attachment.get( 'width' ),
     1928                                realHeight = attachment.get( 'height' ),
     1929                                ratio = xInit / yInit,
     1930                                xImg  = realWidth,
     1931                                yImg  = realHeight,
     1932                                imgSelectOptions;
     1933
     1934                        controller.set( 'canSkipCrop', ! control.mustBeCropped( flexWidth, flexHeight, xInit, yInit, realWidth, realHeight ) );
     1935
     1936                        if ( xImg / yImg > ratio ) {
     1937                                yInit = yImg;
     1938                                xInit = yInit * ratio;
     1939                        } else {
     1940                                xInit = xImg;
     1941                                yInit = xInit / ratio;
     1942                        }
     1943
     1944                        imgSelectOptions = {
     1945                                handles: true,
     1946                                keys: true,
     1947                                instance: true,
     1948                                persistent: true,
     1949                                imageWidth: realWidth,
     1950                                imageHeight: realHeight,
     1951                                x1: 0,
     1952                                y1: 0,
     1953                                x2: xInit,
     1954                                y2: yInit
     1955                        };
     1956
     1957                        if ( flexHeight === false && flexWidth === false ) {
     1958                                imgSelectOptions.aspectRatio = xInit + ':' + yInit;
     1959                        }
     1960                        if ( flexHeight === false ) {
     1961                                imgSelectOptions.maxHeight = yInit;
     1962                        }
     1963                        if ( flexWidth === false ) {
     1964                                imgSelectOptions.maxWidth = xInit;
     1965                        }
     1966
     1967                        return imgSelectOptions;
     1968                },
     1969
     1970                /**
     1971                 * Return whether the image must be cropped, based on required dimensions.
     1972                 */
     1973                mustBeCropped: function( flexW, flexH, dstW, dstH, imgW, imgH ) {
     1974                        if ( flexW === true && flexH === true ) {
     1975                                return false;
     1976                        }
     1977
     1978                        if ( flexW === true && dstH === imgH ) {
     1979                                return false;
     1980                        }
     1981
     1982                        if ( flexH === true && dstW === imgW ) {
     1983                                return false;
     1984                        }
     1985
     1986                        if ( dstW === imgW && dstH === imgH ) {
     1987                                return false;
     1988                        }
     1989
     1990                        if ( imgW <= dstW ) {
     1991                                return false;
     1992                        }
     1993
     1994                        return true;
     1995                },
     1996
     1997                /**
     1998                 * If cropping was skipped, apply the image data directly to the setting.
     1999                 */
     2000                onSkippedCrop: function() {
     2001                        var attachment = this.frame.state().get( 'selection' ).first().toJSON();
     2002                        this.setImageFromAttachment( attachment );
     2003                },
     2004
     2005                /**
     2006                 * Updates the setting and re-renders the control UI.
     2007                 *
     2008                 * @param {object} attachment
     2009                 */
     2010                setImageFromAttachment: function( attachment ) {
     2011                        this.params.attachment = attachment;
     2012
     2013                        // Set the Customizer setting; the callback takes care of rendering.
     2014                        this.setting( attachment.id );
     2015                }
     2016        });
     2017
     2018        /**
     2019         * A control for selecting and cropping Site Icons.
     2020         *
     2021         * @class
     2022         * @augments wp.customize.CroppedImageControl
     2023         * @augments wp.customize.MediaControl
     2024         * @augments wp.customize.Control
     2025         * @augments wp.customize.Class
     2026         */
     2027        api.SiteIconControl = api.CroppedImageControl.extend({
     2028                /**
     2029                 * Updates the setting and re-renders the control UI.
     2030                 *
     2031                 * @param {object} attachment
     2032                 */
     2033                setImageFromAttachment: function( attachment ) {
     2034                        this.params.attachment = attachment;
     2035
     2036                        // Set the Customizer setting; the callback takes care of rendering.
     2037                        this.setting( attachment.id );
     2038
     2039                        // Update the icon in-browser.
     2040                        $( 'link[rel="icon"]' ).attr( 'href', attachment.sizes.thumbnail.url );
     2041                },
     2042
     2043                /**
     2044                 * Called when the "Remove" link is clicked. Empties the setting.
     2045                 *
     2046                 * @param {object} event jQuery Event object
     2047                 */
     2048                removeFile: function( event ) {
     2049                        if ( api.utils.isKeydownButNotEnterEvent( event ) ) {
     2050                                return;
     2051                        }
     2052                        event.preventDefault();
     2053
     2054                        this.params.attachment = {};
     2055                        this.setting( '' );
     2056                        this.renderContent(); // Not bound to setting change when emptying.
     2057                        $( 'link[rel="icon"]' ).attr( 'href', '' );
     2058                }
     2059        });
     2060
     2061        /**
    18392062         * @class
    18402063         * @augments wp.customize.Control
    18412064         * @augments wp.customize.Class
     
    26952918        });
    26962919
    26972920        api.controlConstructor = {
    2698                 color:      api.ColorControl,
    2699                 media:      api.MediaControl,
    2700                 upload:     api.UploadControl,
    2701                 image:      api.ImageControl,
    2702                 header:     api.HeaderControl,
    2703                 background: api.BackgroundControl,
    2704                 theme:      api.ThemeControl
     2921                color:         api.ColorControl,
     2922                media:         api.MediaControl,
     2923                upload:        api.UploadControl,
     2924                image:         api.ImageControl,
     2925                cropped_image: api.CroppedImageControl,
     2926                site_icon:     api.SiteIconControl,
     2927                header:        api.HeaderControl,
     2928                background:    api.BackgroundControl,
     2929                theme:         api.ThemeControl
    27052930        };
    27062931        api.panelConstructor = {};
    27072932        api.sectionConstructor = {
  • src/wp-includes/class-wp-customize-control.php

     
    10011001}
    10021002
    10031003/**
     1004 * Customize Cropped Image Control class.
     1005 *
     1006 * @since 4.3.0
     1007 *
     1008 * @see WP_Customize_Image_Control
     1009 */
     1010class WP_Customize_Cropped_Image_Control extends WP_Customize_Image_Control {
     1011
     1012        /**
     1013         * @access public
     1014         * @var string
     1015         */
     1016        public $type = 'cropped_image';
     1017
     1018        /**
     1019         * @access public
     1020         * @var int
     1021         */
     1022        public $width = 150;
     1023
     1024        /**
     1025         * @access public
     1026         * @var int
     1027         */
     1028        public $height = 150;
     1029
     1030        /**
     1031         * @access public
     1032         * @var bool
     1033         */
     1034        public $flex_width = false;
     1035
     1036        /**
     1037         * @access public
     1038         * @var bool
     1039         */
     1040        public $flex_height = false;
     1041
     1042        /**
     1043         * Enqueue control related scripts/styles.
     1044         *
     1045         * @access public
     1046         */
     1047        public function enqueue() {
     1048                wp_enqueue_script( 'customize-views' );
     1049
     1050                parent::enqueue();
     1051        }
     1052
     1053        /**
     1054         * Refresh the parameters passed to the JavaScript via JSON.
     1055         *
     1056         * @since 4.3.0
     1057         * @access public
     1058         * @uses WP_Customize_Image_Control::to_json()
     1059         *
     1060         * @see WP_Customize_Control::to_json()
     1061         */
     1062        public function to_json() {
     1063                parent::to_json();
     1064
     1065                $this->json['width']       = absint( $this->width );
     1066                $this->json['height']      = absint( $this->height );
     1067                $this->json['flex_width']  = absint( $this->flex_width );
     1068                $this->json['flex_height'] = absint( $this->flex_height );
     1069        }
     1070
     1071}
     1072
     1073/**
     1074 * Customize Site Icon control class.
     1075 *
     1076 * Used only for custom functionality in JavaScript.
     1077 *
     1078 * @since 4.3.0
     1079 *
     1080 * @see WP_Customize_Cropped_Image_Control
     1081 */
     1082class WP_Customize_Site_Icon_Control extends WP_Customize_Cropped_Image_Control {
     1083
     1084        /**
     1085         * @access public
     1086         * @var string
     1087         */
     1088        public $type = 'site_icon';
     1089
     1090        /**
     1091         * Constructor.
     1092         *
     1093         * @since 4.3.0
     1094         *
     1095         * @param WP_Customize_Manager $manager
     1096         * @param string               $id
     1097         * @param array                $args
     1098         */
     1099        public function __construct( $manager, $id, $args = array() ) {
     1100                parent::__construct( $manager, $id, $args );
     1101                add_action( 'customize_controls_print_styles', 'wp_site_icon', 99 );
     1102        }
     1103}
     1104
     1105/**
    10041106 * Customize Header Image Control class.
    10051107 *
    10061108 * @since 3.4.0
  • src/wp-includes/class-wp-customize-manager.php

     
    12781278                $this->register_control_type( 'WP_Customize_Upload_Control' );
    12791279                $this->register_control_type( 'WP_Customize_Image_Control' );
    12801280                $this->register_control_type( 'WP_Customize_Background_Image_Control' );
     1281                $this->register_control_type( 'WP_Customize_Cropped_Image_Control' );
     1282                $this->register_control_type( 'WP_Customize_Site_Icon_Control' );
    12811283                $this->register_control_type( 'WP_Customize_Theme_Control' );
    12821284
    12831285                /* Themes */
     
    13241326                        ) ) );
    13251327                }
    13261328
    1327                 /* Site Title & Tagline */
     1329                /* Site Identity */
    13281330
    13291331                $this->add_section( 'title_tagline', array(
    1330                         'title'    => __( 'Site Title & Tagline' ),
     1332                        'title'    => __( 'Site Identity' ),
    13311333                        'priority' => 20,
    13321334                ) );
    13331335
     
    13531355                        'section'    => 'title_tagline',
    13541356                ) );
    13551357
     1358                $icon = wp_get_attachment_image_src( absint( get_option( 'site_icon' ) ), 'medium' );
     1359                $this->add_setting( 'site_icon', array(
     1360                        'default'    => $icon[0] ? $icon[0] : '',
     1361                        'type'       => 'option',
     1362                        'capability' => 'manage_options',
     1363                        'transport'  => 'postMessage', // Previewed with JS in the Customizer controls window.
     1364                ) );
     1365
     1366                $this->add_control( new WP_Customize_Site_Icon_Control( $this, 'site_icon', array(
     1367                        'label'       => __( 'Site Icon' ),
     1368                        'description' => __( 'The site icon is used as the browser and device icon for your site. Your theme may also display the site icon. Icons must be square, and at least 512px wide and tall.' ),
     1369                        'section'     => 'title_tagline',
     1370                        'priority'    => 60,
     1371                        'height'      => 512,
     1372                        'width'       => 512,
     1373                ) ) );
     1374
    13561375                /* Colors */
    13571376
    13581377                $this->add_section( 'colors', array(
     
    13751394                        'label'    => __( 'Display Header Text' ),
    13761395                        'section'  => 'title_tagline',
    13771396                        'type'     => 'checkbox',
     1397                        'priority' => 40,
    13781398                ) );
    13791399
    13801400                $this->add_control( new WP_Customize_Color_Control( $this, 'header_textcolor', array(
  • src/wp-includes/js/customize-views.js

     
    33        if ( ! wp || ! wp.customize ) { return; }
    44        var api = wp.customize;
    55
     6        /**
     7         * Use a custom ajax action for cropped image controls.
     8         */
     9        wp.media.controller.customizeImageCropper = wp.media.controller.Cropper.extend( {
     10                doCrop: function( attachment ) {
     11                        var cropDetails = attachment.get( 'cropDetails' ),
     12                                control = this.get( 'control' );
     13
     14                        cropDetails.dst_width  = control.params.width;
     15                        cropDetails.dst_height = control.params.height;
     16
     17                        return wp.ajax.post( 'crop-image', {
     18                                wp_customize: 'on',
     19                                nonce: attachment.get( 'nonces' ).edit,
     20                                id: attachment.get( 'id' ),
     21                                context: control.params.type,
     22                                cropDetails: cropDetails
     23                        } );
     24                }
     25        } );
    626
    727        /**
    828         * wp.customize.HeaderTool.CurrentView