Make WordPress Core

Ticket #21483: 21483.3.diff

File 21483.3.diff, 21.6 KB (added by celloexpressions, 10 years ago)

Refresh, plus some additional refinements. Default handling partially implemented.

  • src/wp-admin/css/customize-controls.css

     
    1010        font-size: 14px;
    1111}
    1212
     13#customize-controls img {
     14        max-width: 100%;
     15}
     16
    1317#customize-controls .submit {
    1418        text-align: center;
    1519}
     
    414418        margin-right: 5px;
    415419}
    416420
     421.customize-control .attachment-thumb.type-icon {
     422        float: left;
     423        margin-right: 12px;
     424}
     425
     426.customize-control .attachment-title {
     427        font-weight: bold;
     428        margin: 0 0 12px 0;
     429}
     430
     431.customize-control .remove-button {
     432        margin-left: 8px;
     433        vertical-align: middle;
     434}
     435
     436.customize-control .thumbnail-audio .attachment-title,
     437.customize-control .thumbnail.thumbnail-audio,
     438.customize-control .thumbnail.thumbnail-video,
     439.customize-control .thumbnail.thumbnail-image {
     440        margin-bottom: 8px;
     441}
     442
    417443#customize-preview iframe {
    418444        width: 100%;
    419445        height: 100%;
  • src/wp-admin/js/customize-controls.js

     
    883883         * @augments wp.customize.Class
    884884         */
    885885        api.UploadControl = api.Control.extend({
    886                 ready: function() {
     886
     887                /**
     888                 * Set up control and do event bindings.
     889                 */
     890                ready: function() {
    887891                        var control = this;
    888892
    889                         this.params.removed = this.params.removed || '';
     893                        control.setupEvents();
     894                        control.setting.bind( function () { control.reRender() } )
     895                },
    890896
    891                         this.success = $.proxy( this.success, this );
     897                setupEvents: function() {
     898                        // Cache buttons for re-use.
     899                        this.$button = this.container.find( '.upload-button' );
     900                        this.$img = this.container.find( '.thumbnail-image img' );
     901                        this.$defaultButton = this.container.find( '.default-button' );
     902                        this.$removeButton = this.container.find( '.remove-button' );
    892903
    893                         this.uploader = $.extend({
    894                                 container: this.container,
    895                                 browser:   this.container.find('.upload'),
    896                                 dropzone:  this.container.find('.upload-dropzone'),
    897                                 success:   this.success,
    898                                 plupload:  {},
    899                                 params:    {}
    900                         }, this.uploader || {} );
     904                        // Shortcut so that we don't have to use _.bind every time we add a callback.
     905                        _.bindAll( this, 'removeFile', 'reRender', 'openFrame', 'select' );
    901906
    902                         if ( control.params.extensions ) {
    903                                 control.uploader.plupload.filters = [{
    904                                         title:      api.l10n.allowedFiles,
    905                                         extensions: control.params.extensions
    906                                 }];
    907                         }
     907                        this.$defaultButton.on( 'click keydown', this.restoreDefault );
     908                        this.$removeButton.on( 'click keydown', this.removeFile );
     909                        this.$button.on( 'click keydown', this.openFrame );
     910                        this.$img.on( 'click keydown', this.openFrame );
     911                },
    908912
    909                         if ( control.params.context )
    910                                 control.uploader.params['post_data[context]'] = this.params.context;
     913                /**
     914                 * Open the media modal.
     915                 */
     916                openFrame: function( event ) {
     917                        if ( event.type === 'keydown' &&  13 !== event.which ) { // enter
     918                                return;
     919                        }
    911920
    912                         if ( api.settings.theme.stylesheet )
    913                                 control.uploader.params['post_data[theme]'] = api.settings.theme.stylesheet;
     921                        event.preventDefault();
     922 
     923                        if ( ! this.frame ) {
     924                                this.initFrame();
     925                        }
    914926
    915                         this.uploader = new wp.Uploader( this.uploader );
     927                        this.frame.open();
     928                },
    916929
    917                         this.remover = this.container.find('.remove');
    918                         this.remover.on( 'click keydown', function( event ) {
    919                                 if ( isKeydownButNotEnterEvent( event ) ) {
    920                                         return;
    921                                 }
     930                /**
     931                 * Set up the media modal so that it can be reused and accessed when needed.
     932                 */
     933                initFrame: function() {
     934                        this.frame = wp.media({
     935                                // The title of the media modal.
     936                                title: this.params.button_labels.frame_title,
     937 
     938                                // Restrict to specified mime type.
     939                                // @todo try to map $extensions to this in PHP?
     940                                library: {
     941                                        type: this.params.mime_type
     942                                },
     943                                button: {
     944                                        // Change the submit button label.
     945                                        text: this.params.button_labels.frame_button
     946                                },
     947                                multiple: false
     948                        });
     949 
     950                        // When a file is selected, run a callback.
     951                        this.frame.on( 'select', this.select );
     952                },
    922953
    923                                 control.setting.set( control.params.removed );
    924                                 event.preventDefault();
    925                         });
     954                /**
     955                 * Fired when an attachment is selected in the media modal. Gets the selected
     956                 * image information, and sets it within the control.
     957                 */
     958                select: function() {
     959                        // Get the attachment from the modal frame.
     960                        var attachment = this.frame.state().get( 'selection' ).first().toJSON();
     961 
     962                        this.params.attachment = attachment;
     963 
     964                        // Set the Customizer setting; the callback takes care of rendering.
     965                        this.setting( attachment.url );
     966                },
    926967
    927                         this.removerVisibility = $.proxy( this.removerVisibility, this );
    928                         this.setting.bind( this.removerVisibility );
    929                         this.removerVisibility( this.setting.get() );
     968                /**
     969                 * Called on whenever a setting is changed.
     970                 */
     971                reRender: function() {
     972                        this.container.html('');
     973                        this.renderContent();
     974                        this.setupEvents();
     975                        // @todo: something else is needed to preview audio/video files
    930976                },
    931                 success: function( attachment ) {
    932                         this.setting.set( attachment.get('url') );
    933                 },
    934                 removerVisibility: function( to ) {
    935                         this.remover.toggle( to != this.params.removed );
    936                 }
    937         });
    938977
    939         /**
    940          * @constructor
    941          * @augments wp.customize.UploadControl
    942          * @augments wp.customize.Control
    943          * @augments wp.customize.Class
    944          */
    945         api.ImageControl = api.UploadControl.extend({
    946                 ready: function() {
    947                         var control = this,
    948                                 panels;
    949 
    950                         this.uploader = {
    951                                 init: function() {
    952                                         var fallback, button;
    953 
    954                                         if ( this.supports.dragdrop )
    955                                                 return;
    956 
    957                                         // Maintain references while wrapping the fallback button.
    958                                         fallback = control.container.find( '.upload-fallback' );
    959                                         button   = fallback.children().detach();
    960 
    961                                         this.browser.detach().empty().append( button );
    962                                         fallback.append( this.browser ).show();
    963                                 }
    964                         };
    965 
    966                         api.UploadControl.prototype.ready.call( this );
    967 
    968                         this.thumbnail    = this.container.find('.preview-thumbnail img');
    969                         this.thumbnailSrc = $.proxy( this.thumbnailSrc, this );
    970                         this.setting.bind( this.thumbnailSrc );
    971 
    972                         this.library = this.container.find('.library');
    973 
    974                         // Generate tab objects
    975                         this.tabs = {};
    976                         panels    = this.library.find('.library-content');
    977 
    978                         this.library.children('ul').children('li').each( function() {
    979                                 var link  = $(this),
    980                                         id    = link.data('customizeTab'),
    981                                         panel = panels.filter('[data-customize-tab="' + id + '"]');
    982 
    983                                 control.tabs[ id ] = {
    984                                         both:  link.add( panel ),
    985                                         link:  link,
    986                                         panel: panel
    987                                 };
    988                         });
    989 
    990                         // Bind tab switch events
    991                         this.library.children('ul').on( 'click keydown', 'li', function( event ) {
    992                                 if ( isKeydownButNotEnterEvent( event ) ) {
    993                                         return;
    994                                 }
    995 
    996                                 var id  = $(this).data('customizeTab'),
    997                                         tab = control.tabs[ id ];
    998 
    999                                 event.preventDefault();
    1000 
    1001                                 if ( tab.link.hasClass('library-selected') )
    1002                                         return;
    1003 
    1004                                 control.selected.both.removeClass('library-selected');
    1005                                 control.selected = tab;
    1006                                 control.selected.both.addClass('library-selected');
    1007                         });
    1008 
    1009                         // Bind events to switch image urls.
    1010                         this.library.on( 'click keydown', 'a', function( event ) {
    1011                                 if ( isKeydownButNotEnterEvent( event ) ) {
    1012                                         return;
    1013                                 }
    1014 
    1015                                 var value = $(this).data('customizeImageValue');
    1016 
    1017                                 if ( value ) {
    1018                                         control.setting.set( value );
    1019                                         event.preventDefault();
    1020                                 }
    1021                         });
    1022 
    1023                         if ( this.tabs.uploaded ) {
    1024                                 this.tabs.uploaded.target = this.library.find('.uploaded-target');
    1025                                 if ( ! this.tabs.uploaded.panel.find('.thumbnail').length )
    1026                                         this.tabs.uploaded.both.addClass('hidden');
     978                /**
     979                 * Reset the setting to the default value. @todo default button instead of remove that calls this.
     980                 */
     981                restoreDefault: function( event ) {
     982                        if ( event.type === 'keydown' &&  13 !== event.which ) { // enter
     983                                return;
    1027984                        }
    1028985
    1029                         // Select a tab
    1030                         panels.each( function() {
    1031                                 var tab = control.tabs[ $(this).data('customizeTab') ];
     986                        event.preventDefault();
     987                        this.setting( this.params.defaultAttachment.url );
     988                        this.params.attachment = this.params.defaultAttachment;
     989                },
    1032990
    1033                                 // Select the first visible tab.
    1034                                 if ( ! tab.link.hasClass('hidden') ) {
    1035                                         control.selected = tab;
    1036                                         tab.both.addClass('library-selected');
    1037                                         return false;
    1038                                 }
    1039                         });
     991                /**
     992                 * Called when the "Remove" link is clicked. Empties the setting.
     993                 * @param {object} event jQuery Event object
     994                 */
     995                removeFile: function( event ) {
     996                        if ( event.type === 'keydown' &&  13 !== event.which ) { // enter
     997                                return;
     998                        }
    1040999
    1041                         this.dropdownInit();
    1042                 },
    1043                 success: function( attachment ) {
    1044                         api.UploadControl.prototype.success.call( this, attachment );
     1000                        event.preventDefault();
     1001                        this.params.attachment = {};
     1002                        this.setting( '' );
     1003                }
     1004        });
    10451005
    1046                         // Add the uploaded image to the uploaded tab.
    1047                         if ( this.tabs.uploaded && this.tabs.uploaded.target.length ) {
    1048                                 this.tabs.uploaded.both.removeClass('hidden');
    1049 
    1050                                 // @todo: Do NOT store this on the attachment model. That is bad.
    1051                                 attachment.element = $( '<a href="#" class="thumbnail"></a>' )
    1052                                         .data( 'customizeImageValue', attachment.get('url') )
    1053                                         .append( '<img src="' +  attachment.get('url')+ '" />' )
    1054                                         .appendTo( this.tabs.uploaded.target );
    1055                         }
    1056                 },
    1057                 thumbnailSrc: function( to ) {
    1058                         if ( /^(https?:)?\/\//.test( to ) )
    1059                                 this.thumbnail.prop( 'src', to ).show();
    1060                         else
    1061                                 this.thumbnail.hide();
    1062                 }
    1063         });
    1064 
    10651006        /**
    10661007         * @constructor
    10671008         * @augments wp.customize.Control
     
    17021643        api.controlConstructor = {
    17031644                color:  api.ColorControl,
    17041645                upload: api.UploadControl,
    1705                 image:  api.ImageControl,
    17061646                header: api.HeaderControl
    17071647        };
    17081648        api.panelConstructor = {};
  • src/wp-includes/class-wp-customize-control.php

     
    613613 * @since 3.4.0
    614614 */
    615615class WP_Customize_Upload_Control extends WP_Customize_Control {
    616         public $type    = 'upload';
    617         public $removed = '';
    618         public $context;
    619         public $extensions = array();
     616        public $type     = 'upload';
     617        public $mime_type = '';
     618        public $button_labels = array(
     619                'select' => 'Select File', // @todo PHP doesn't like letting us translate these
     620                'change' => 'Change File',
     621                'remove' => 'Remove',
     622                'frame_title' => 'Select File',
     623                'frame_button' => 'Choose File',
     624        );
     625        public $removed = ''; // unused
     626        public $context; // unused
     627        public $extensions = array(); // unused
    620628
    621629        /**
    622630         * Enqueue control related scripts/styles.
     
    624632         * @since 3.4.0
    625633         */
    626634        public function enqueue() {
    627                 wp_enqueue_script( 'wp-plupload' );
     635                wp_enqueue_media();
    628636        }
    629637
    630638        /**
     
    635643         */
    636644        public function to_json() {
    637645                parent::to_json();
     646                $this->json['mime_type'] = $this->mime_type;
     647                $this->json['button_labels'] = $this->button_labels;
    638648
    639                 $this->json['removed'] = $this->removed;
     649                if ( $this->setting ) {
     650                        if ( $this->settings['default']->value() ) {
     651                                // @todo:
     652                                // generate an attachment object & prepare for js (or fake it - needs all fields used by template)
     653                                // $this->json['defaultAttachment'] = $default_attachment;
     654                        }
    640655
    641                 if ( $this->context )
    642                         $this->json['context'] = $this->context;
    643 
    644                 if ( $this->extensions )
    645                         $this->json['extensions'] = implode( ',', $this->extensions );
     656                        // Get the attachment model for the existing file, or make one.
     657                        if ( $this->value() ) {
     658                                $attachment_id = attachment_url_to_postid( $this->value() );
     659                                if ( $attachment_id ) {
     660                                        $this->json['attachment'] = wp_prepare_attachment_for_js( $attachment_id);
     661                                }
     662                        }
     663                }
    646664        }
    647665
    648666        /**
    649          * Render the control's content.
     667         * Don't render any content for this control from PHP.
    650668         *
     669         * @see WP_Customize_Upload_Control::content_template()
    651670         * @since 3.4.0
    652671         */
    653         public function render_content() {
     672        public function render_content() {}
     673
     674        /**
     675         * Render a JS template for the content of the upload control.
     676         *
     677         * @since 4.1.0
     678         */
     679        public function content_template() {
    654680                ?>
    655681                <label>
    656                         <?php if ( ! empty( $this->label ) ) : ?>
    657                                 <span class="customize-control-title"><?php echo esc_html( $this->label ); ?></span>
    658                         <?php endif;
    659                         if ( ! empty( $this->description ) ) : ?>
    660                                 <span class="description customize-control-description"><?php echo $this->description; ?></span>
    661                         <?php endif; ?>
    662                         <div>
    663                                 <a href="#" class="button-secondary upload"><?php _e( 'Upload' ); ?></a>
    664                                 <a href="#" class="remove"><?php _e( 'Remove' ); ?></a>
    665                         </div>
     682                        <# if ( data.label ) { #>
     683                                <span class="customize-control-title">{{ data.label }}</span>
     684                        <# } #>
     685                        <# if ( data.description ) { #>
     686                                <span class="description customize-control-description">{{ data.description }}</span>
     687                        <# } #>
     688
     689                        <# if ( data.attachment && data.attachment.id ) { #>
     690                                <div class="attachment-media-view {{ data.attachment.orientation }}">
     691                                        <div class="thumbnail thumbnail-{{ data.attachment.type }}">
     692                                                <# if ( 'image' === data.attachment.type && data.attachment.sizes && data.attachment.sizes.medium ) { #>
     693                                                        <img class="attachment-thumb" src="{{ data.attachment.sizes.medium.url }}" draggable="false" />
     694                                                <# } else if ( 'image' === data.attachment.type && data.attachment.sizes && data.attachment.sizes.full ) { #>
     695                                                        <img class="attachment-thumb" src="{{ data.attachment.sizes.full.url }}" draggable="false" />
     696                                                <# } else if ( -1 === jQuery.inArray( data.attachment.type, [ 'audio', 'video' ] ) ) { #>
     697                                                        <img class="attachment-thumb type-icon" src="{{ data.attachment.icon }}" class="icon" draggable="false" />
     698                                                        <p class="attachment-title">{{ data.attachment.title }}</p>
     699                                                <# } #>
     700
     701                                                <# if ( 'audio' === data.attachment.type ) { #>
     702                                                <div class="wp-media-wrapper">
     703                                                        <p class="attachment-title">{{ data.attachment.title }}</p>
     704                                                        <audio style="visibility: hidden" controls class="wp-audio-shortcode" width="100%" preload="none">
     705                                                                <source type="{{ data.attachment.mime }}" src="{{ data.attachment.url }}"/>
     706                                                        </audio>
     707                                                </div>
     708                                                <# } else if ( 'video' === data.attachment.type ) {
     709                                                        var w_rule = h_rule = '';
     710                                                        if ( data.attachment.width ) {
     711                                                                w_rule = 'width: ' + data.attachment.width + 'px;';
     712                                                        } else if ( wp.media.view.settings.contentWidth ) {
     713                                                                w_rule = 'width: ' + wp.media.view.settings.contentWidth + 'px;';
     714                                                        }
     715                                                        if ( data.attachment.height ) {
     716                                                                h_rule = 'height: ' + data.attachment.height + 'px;';
     717                                                        }
     718                                                        #>
     719                                                        <div style="{{ w_rule }}{{ h_rule }}" class="wp-media-wrapper wp-video">
     720                                                                <video controls="controls" class="wp-video-shortcode" preload="metadata"
     721                                                                        <# if ( data.attachment.width ) { #>width="{{ data.attachment.width }}"<# } #>
     722                                                                        <# if ( data.attachment.height ) { #>height="{{ data.attachment.height }}"<# } #>
     723                                                                        <# if ( data.attachment.image && data.attachment.image.src !== data.attachment.icon ) { #>poster="{{ data.attachment.image.src }}"<# } #>>
     724                                                                        <source type="{{ data.attachment.mime }}" src="{{ data.attachment.url }}"/>
     725                                                                </video>
     726                                                        </div>
     727                                                <# } #>
     728                                        </div>
     729                                </div>
     730                                <a class="button upload-button" href="#"><?php echo $this->button_labels['change']; ?></a>
     731                                <# if ( data.defaultAttachmet && data.defaultAttachment.id !== data.attachment.id ) { #>
     732                                        <a class="default-button remove-button" href="#"><?php echo $this->button_labels['default']; ?></a>
     733                                <# } else { #>
     734                                        <a class="remove-button" href="#"><?php echo $this->button_labels['remove']; ?></a>
     735                                <# } #>
     736                        <# } else { #>
     737                                <a class="button upload-button" href="#"><?php echo $this->button_labels['select']; ?></a>
     738                        <# } #>
    666739                </label>
    667740                <?php
    668741        }
     
    676749 * @since 3.4.0
    677750 */
    678751class WP_Customize_Image_Control extends WP_Customize_Upload_Control {
    679         public $type = 'image';
    680         public $get_url;
    681         public $statuses;
    682         public $extensions = array( 'jpg', 'jpeg', 'gif', 'png' );
     752        public $mime_type = 'image';
     753        public $button_labels = array(
     754                'select' => 'Select Image', // @todo PHP doesn't like letting us translate these
     755                'change' => 'Change Image',
     756                'remove' => 'Remove',
     757                'frame_title' => 'Select Image',
     758                'frame_button' => 'Choose Image',
     759        );
    683760
    684         protected $tabs = array();
    685 
    686761        /**
    687          * Constructor.
    688          *
    689          * @since 3.4.0
    690          * @uses WP_Customize_Upload_Control::__construct()
    691          *
    692          * @param WP_Customize_Manager $manager
    693          * @param string $id
    694          * @param array $args
    695          */
    696         public function __construct( $manager, $id, $args ) {
    697                 $this->statuses = array( '' => __('No Image') );
    698 
    699                 parent::__construct( $manager, $id, $args );
    700 
    701                 $this->add_tab( 'upload-new', __('Upload New'), array( $this, 'tab_upload_new' ) );
    702                 $this->add_tab( 'uploaded',   __('Uploaded'),   array( $this, 'tab_uploaded' ) );
    703 
    704                 // Early priority to occur before $this->manager->prepare_controls();
    705                 add_action( 'customize_controls_init', array( $this, 'prepare_control' ), 5 );
    706         }
    707 
    708         /**
    709          * Prepares the control.
    710          *
    711          * If no tabs exist, removes the control from the manager.
    712          *
    713762         * @since 3.4.2
     763         * @deprecated 4.1.0
    714764         */
    715         public function prepare_control() {
    716                 if ( ! $this->tabs )
    717                         $this->manager->remove_control( $this->id );
    718         }
     765        public function prepare_control() {}
    719766
    720767        /**
    721          * Refresh the parameters passed to the JavaScript via JSON.
    722          *
    723768         * @since 3.4.0
    724          * @uses WP_Customize_Upload_Control::to_json()
    725          */
    726         public function to_json() {
    727                 parent::to_json();
    728                 $this->json['statuses'] = $this->statuses;
    729         }
    730 
    731         /**
    732          * Render the control's content.
     769         * @deprecated 4.1.0
    733770         *
    734          * @since 3.4.0
    735          */
    736         public function render_content() {
    737                 $src = $this->value();
    738                 if ( isset( $this->get_url ) )
    739                         $src = call_user_func( $this->get_url, $src );
    740 
    741                 ?>
    742                 <div class="customize-image-picker">
    743                         <?php if ( ! empty( $this->label ) ) : ?>
    744                                 <span class="customize-control-title"><?php echo esc_html( $this->label ); ?></span>
    745                         <?php endif;
    746                         if ( ! empty( $this->description ) ) : ?>
    747                                 <span class="description customize-control-description"><?php echo $this->description; ?></span>
    748                         <?php endif; ?>
    749 
    750                         <div class="customize-control-content">
    751                                 <div class="dropdown preview-thumbnail" tabindex="0">
    752                                         <div class="dropdown-content">
    753                                                 <?php if ( empty( $src ) ): ?>
    754                                                         <img style="display:none;" />
    755                                                 <?php else: ?>
    756                                                         <img src="<?php echo esc_url( set_url_scheme( $src ) ); ?>" />
    757                                                 <?php endif; ?>
    758                                                 <div class="dropdown-status"></div>
    759                                         </div>
    760                                         <div class="dropdown-arrow"></div>
    761                                 </div>
    762                         </div>
    763 
    764                         <div class="library">
    765                                 <ul>
    766                                         <?php foreach ( $this->tabs as $id => $tab ): ?>
    767                                                 <li data-customize-tab='<?php echo esc_attr( $id ); ?>' tabindex='0'>
    768                                                         <?php echo esc_html( $tab['label'] ); ?>
    769                                                 </li>
    770                                         <?php endforeach; ?>
    771                                 </ul>
    772                                 <?php foreach ( $this->tabs as $id => $tab ): ?>
    773                                         <div class="library-content" data-customize-tab='<?php echo esc_attr( $id ); ?>'>
    774                                                 <?php call_user_func( $tab['callback'] ); ?>
    775                                         </div>
    776                                 <?php endforeach; ?>
    777                         </div>
    778 
    779                         <div class="actions">
    780                                 <a href="#" class="remove"><?php _e( 'Remove Image' ); ?></a>
    781                         </div>
    782                 </div>
    783                 <?php
    784         }
    785 
    786         /**
    787          * Add a tab to the control.
    788          *
    789          * @since 3.4.0
    790          *
    791771         * @param string $id
    792772         * @param string $label
    793773         * @param mixed $callback
    794774         */
    795         public function add_tab( $id, $label, $callback ) {
    796                 $this->tabs[ $id ] = array(
    797                         'label'    => $label,
    798                         'callback' => $callback,
    799                 );
    800         }
     775        public function add_tab( $id, $label, $callback ) {}
    801776
    802777        /**
    803          * Remove a tab from the control.
    804          *
    805778         * @since 3.4.0
     779         * @deprecated 4.1.0
    806780         *
    807781         * @param string $id
    808782         */
    809         public function remove_tab( $id ) {
    810                 unset( $this->tabs[ $id ] );
    811         }
     783        public function remove_tab( $id ) {}
    812784
    813785        /**
    814786         * @since 3.4.0
    815          */
    816         public function tab_upload_new() {
    817                 if ( ! _device_can_upload() ) {
    818                         echo '<p>' . sprintf( __('The web browser on your device cannot be used to upload files. You may be able to use the <a href="%s">native app for your device</a> instead.'), 'https://apps.wordpress.org/' ) . '</p>';
    819                 } else {
    820                         ?>
    821                         <div class="upload-dropzone">
    822                                 <?php _e('Drop a file here or <a href="#" class="upload">select a file</a>.'); ?>
    823                         </div>
    824                         <div class="upload-fallback">
    825                                 <span class="button-secondary"><?php _e('Select File'); ?></span>
    826                         </div>
    827                         <?php
    828                 }
    829         }
    830 
    831         /**
    832          * @since 3.4.0
    833          */
    834         public function tab_uploaded() {
    835                 ?>
    836                 <div class="uploaded-target"></div>
    837                 <?php
    838         }
    839 
    840         /**
    841          * @since 3.4.0
     787         * @deprecated 4.1.0
    842788         *
    843789         * @param string $url
    844790         * @param string $thumbnail_url
    845791         */
    846         public function print_tab_image( $url, $thumbnail_url = null ) {
    847                 $url = set_url_scheme( $url );
    848                 $thumbnail_url = ( $thumbnail_url ) ? set_url_scheme( $thumbnail_url ) : $url;
    849                 ?>
    850                 <a href="#" class="thumbnail" data-customize-image-value="<?php echo esc_url( $url ); ?>">
    851                         <img src="<?php echo esc_url( $thumbnail_url ); ?>" />
    852                 </a>
    853                 <?php
    854         }
     792        public function print_tab_image( $url, $thumbnail_url = null ) {}
    855793}
    856794
    857795/**
  • src/wp-includes/class-wp-customize-manager.php

     
    970970
    971971                /* Control Types (custom control classes) */
    972972                $this->register_control_type( 'WP_Customize_Color_Control' );
     973                $this->register_control_type( 'WP_Customize_Upload_Control' );
     974                $this->register_control_type( 'WP_Customize_Image_Control' );
    973975
    974976                /* Site Title & Tagline */
    975977