WordPress.org

Make WordPress Core

Ticket #16434: 16434.15.diff

File 16434.15.diff, 19.2 KB (added by obenland, 23 months 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