Ticket #21483: 21483.8.diff
File 21483.8.diff, 28.9 KB (added by , 10 years ago) |
---|
-
src/wp-admin/css/customize-controls.css
10 10 font-size: 14px; 11 11 } 12 12 13 #customize-controls img { 14 max-width: 100%; 15 } 16 13 17 #customize-controls .submit { 14 18 text-align: center; 15 19 } … … 414 418 margin-right: 5px; 415 419 } 416 420 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 443 .customize-control .placeholder-text { 444 font-size: 18px; 445 font-weight: 300; 446 text-align: center; 447 color: #aaa; 448 cursor: default; 449 } 450 451 .customize-control .thumbnail-image img { 452 cursor: pointer; 453 } 454 417 455 #customize-preview iframe { 418 456 width: 100%; 419 457 height: 100%; -
src/wp-admin/js/customize-controls.js
5 5 // @todo Move private helper functions to wp.customize.utils so they can be unit tested 6 6 7 7 /** 8 * @c onstructor8 * @class 9 9 * @augments wp.customize.Value 10 10 * @augments wp.customize.Class 11 11 * … … 127 127 /** 128 128 * Base class for Panel and Section 129 129 * 130 * @c onstructor130 * @class 131 131 * @augments wp.customize.Class 132 132 */ 133 133 Container = api.Class.extend({ … … 312 312 }); 313 313 314 314 /** 315 * @c onstructor315 * @class 316 316 * @augments wp.customize.Class 317 317 */ 318 318 api.Section = Container.extend({ … … 467 467 }); 468 468 469 469 /** 470 * @c onstructor470 * @class 471 471 * @augments wp.customize.Class 472 472 */ 473 473 api.Panel = Container.extend({ … … 636 636 }); 637 637 638 638 /** 639 * @constructor 639 * A Customizer Control. 640 * 641 * A control provides a UI element that allows a user to modify a Customizer Setting. 642 * 643 * @see PHP class WP_Customize_Control. 644 * 645 * @class 640 646 * @augments wp.customize.Class 647 * 648 * @param {string} id Unique identifier for the control instance. 649 * @param {object} options Options hash for the control instance. 650 * @param {object} options.params 651 * @param {object} options.params.type Type of control (e.g. text, radio, dropdown-pages, etc.) 652 * @param {string} options.params.content The HTML content for the control. 653 * @param {string} options.params.priority Order of priority to show the control within the section. 654 * @param {string} options.params.active 655 * @param {string} options.params.section 656 * @param {string} options.params.label 657 * @param {string} options.params.description 658 * @param {string} options.params.instanceNumber Order in which this instance was created in relation to other instances. 641 659 */ 642 660 api.Control = api.Class.extend({ 643 661 defaultActiveArguments: { duration: 'fast' }, … … 648 666 649 667 control.params = {}; 650 668 $.extend( control, options || {} ); 651 652 669 control.id = id; 653 670 control.selector = '#customize-control-' + id.replace( /\]/g, '' ).replace( /\[/g, '-' ); 654 671 control.templateSelector = 'customize-control-' + control.params.type + '-content'; … … 724 741 }, 725 742 726 743 /** 727 * 744 * Embed the control into the page. 728 745 */ 729 746 embed: function () { 730 747 var control = this, … … 754 771 }, 755 772 756 773 /** 774 * Triggered when the control's markup has been injected into the DOM. 775 * 757 776 * @abstract 758 777 */ 759 778 ready: function() {}, … … 857 876 var template, 858 877 control = this; 859 878 879 // Replace the container element's content with the control. 860 880 if ( 0 !== $( '#tmpl-' + control.templateSelector ).length ) { 861 881 template = wp.template( control.templateSelector ); 862 882 if ( template && control.container ) { 863 control.container. append( template( control.params ) );883 control.container.html( template( control.params ) ); 864 884 } 865 885 } 866 886 } … … 867 887 }); 868 888 869 889 /** 870 * @constructor 890 * A colorpicker control. 891 * 892 * @class 871 893 * @augments wp.customize.Control 872 894 * @augments wp.customize.Class 873 895 */ … … 893 915 }); 894 916 895 917 /** 896 * @constructor 918 * An upload control, which utilizes the media modal. 919 * 920 * @class 897 921 * @augments wp.customize.Control 898 922 * @augments wp.customize.Class 899 923 */ 900 924 api.UploadControl = api.Control.extend({ 901 ready: function() { 925 926 /** 927 * When the control's DOM structure is ready, 928 * set up internal event bindings. 929 */ 930 ready: function() { 902 931 var control = this; 932 // Shortcut so that we don't have to use _.bind every time we add a callback. 933 _.bindAll( control, 'restoreDefault', 'removeFile', 'openFrame', 'select' ); 903 934 904 this.params.removed = this.params.removed || ''; 935 // Bind events, with delegation to facilitate re-rendering. 936 control.container.on( 'click keydown', '.upload-button', control.openFrame ); 937 control.container.on( 'click keydown', '.thumbnail-image img', control.openFrame ); 938 control.container.on( 'click keydown', '.default-button', control.restoreDefault ); 939 control.container.on( 'click keydown', '.remove-button', control.removeFile ); 905 940 906 this.success = $.proxy( this.success, this ); 941 // Re-render whenever the control's setting changes. 942 control.setting.bind( function () { control.renderContent(); } ); 943 }, 907 944 908 this.uploader = $.extend({ 909 container: this.container, 910 browser: this.container.find('.upload'), 911 dropzone: this.container.find('.upload-dropzone'), 912 success: this.success, 913 plupload: {}, 914 params: {} 915 }, this.uploader || {} ); 945 /** 946 * Open the media modal. 947 */ 948 openFrame: function( event ) { 949 if ( event.type === 'keydown' && 13 !== event.which ) { // enter 950 return; 951 } 916 952 917 if ( control.params.extensions ) { 918 control.uploader.plupload.filters = [{ 919 title: api.l10n.allowedFiles, 920 extensions: control.params.extensions 921 }]; 953 event.preventDefault(); 954 955 if ( ! this.frame ) { 956 this.initFrame(); 922 957 } 923 958 924 if ( control.params.context ) 925 control.uploader.params['post_data[context]'] = this.params.context; 926 927 if ( api.settings.theme.stylesheet ) 928 control.uploader.params['post_data[theme]'] = api.settings.theme.stylesheet; 929 930 this.uploader = new wp.Uploader( this.uploader ); 931 932 this.remover = this.container.find('.remove'); 933 this.remover.on( 'click keydown', function( event ) { 934 if ( isKeydownButNotEnterEvent( event ) ) { 935 return; 936 } 937 938 control.setting.set( control.params.removed ); 939 event.preventDefault(); 940 }); 941 942 this.removerVisibility = $.proxy( this.removerVisibility, this ); 943 this.setting.bind( this.removerVisibility ); 944 this.removerVisibility( this.setting.get() ); 959 this.frame.open(); 945 960 }, 946 success: function( attachment ) {947 this.setting.set( attachment.get('url') );948 },949 removerVisibility: function( to ) {950 this.remover.toggle( to != this.params.removed );951 }952 });953 961 954 /** 955 * @constructor 956 * @augments wp.customize.UploadControl 957 * @augments wp.customize.Control 958 * @augments wp.customize.Class 959 */ 960 api.ImageControl = api.UploadControl.extend({ 961 ready: function() { 962 var control = this, 963 panels; 962 /** 963 * Create a media modal select frame, and store it so the instance can be reused when needed. 964 */ 965 initFrame: function() { 966 this.frame = wp.media({ 967 // The title of the media modal. 968 title: this.params.button_labels.frame_title, 964 969 965 this.uploader = { 966 init: function() { 967 var fallback, button; 970 // Restrict the library to specified mime type. 971 library: { 972 type: this.params.mime_type 973 }, 974 button: { 975 // Change the submit button label. 976 text: this.params.button_labels.frame_button 977 }, 978 multiple: false 979 }); 968 980 969 if ( this.supports.dragdrop ) 970 return; 981 // When a file is selected, run a callback. 982 this.frame.on( 'select', this.select ); 983 }, 971 984 972 // Maintain references while wrapping the fallback button. 973 fallback = control.container.find( '.upload-fallback' ); 974 button = fallback.children().detach(); 985 /** 986 * Callback handler for when an attachment is selected in the media modal. 987 * Gets the selected image information, and sets it within the control. 988 */ 989 select: function() { 990 // Get the attachment from the modal frame. 991 var attachment = this.frame.state().get( 'selection' ).first().toJSON(); 975 992 976 this.browser.detach().empty().append( button ); 977 fallback.append( this.browser ).show(); 978 } 979 }; 993 this.params.attachment = attachment; 980 994 981 api.UploadControl.prototype.ready.call( this ); 995 // Set the Customizer setting; the callback takes care of rendering. 996 this.setting( attachment.url ); 997 }, 982 998 983 this.thumbnail = this.container.find('.preview-thumbnail img'); 984 this.thumbnailSrc = $.proxy( this.thumbnailSrc, this ); 985 this.setting.bind( this.thumbnailSrc ); 999 /** 1000 * Reset the setting to the default value. 1001 */ 1002 restoreDefault: function( event ) { 1003 if ( event.type === 'keydown' && 13 !== event.which ) { // enter 1004 return; 1005 } 1006 event.preventDefault(); 986 1007 987 this.library = this.container.find('.library'); 1008 this.params.attachment = this.params.defaultAttachment; 1009 this.setting( this.params.defaultAttachment.url ); 1010 }, 988 1011 989 // Generate tab objects 990 this.tabs = {}; 991 panels = this.library.find('.library-content'); 1012 /** 1013 * Called when the "Remove" link is clicked. Empties the setting. 1014 * 1015 * @param {object} event jQuery Event object 1016 */ 1017 removeFile: function( event ) { 1018 if ( event.type === 'keydown' && 13 !== event.which ) { // enter 1019 return; 1020 } 1021 event.preventDefault(); 992 1022 993 this. library.children('ul').children('li').each( function() {994 var link = $(this),995 id = link.data('customizeTab'),996 panel = panels.filter('[data-customize-tab="' + id + '"]'); 1023 this.params.attachment = {}; 1024 this.setting( '' ); 1025 this.renderContent(); // Not bound to setting change when emptying. 1026 }, 997 1027 998 control.tabs[ id ] = { 999 both: link.add( panel ), 1000 link: link, 1001 panel: panel 1002 }; 1003 }); 1028 // @deprecated 1029 success: function( attachment ) {}, 1004 1030 1005 // Bind tab switch events 1006 this.library.children('ul').on( 'click keydown', 'li', function( event ) { 1007 if ( isKeydownButNotEnterEvent( event ) ) { 1008 return; 1009 } 1031 // @deprecated 1032 removerVisibility: function( to ) {} 1033 }); 1010 1034 1011 var id = $(this).data('customizeTab'), 1012 tab = control.tabs[ id ]; 1013 1014 event.preventDefault(); 1015 1016 if ( tab.link.hasClass('library-selected') ) 1017 return; 1018 1019 control.selected.both.removeClass('library-selected'); 1020 control.selected = tab; 1021 control.selected.both.addClass('library-selected'); 1022 }); 1023 1024 // Bind events to switch image urls. 1025 this.library.on( 'click keydown', 'a', function( event ) { 1026 if ( isKeydownButNotEnterEvent( event ) ) { 1027 return; 1028 } 1029 1030 var value = $(this).data('customizeImageValue'); 1031 1032 if ( value ) { 1033 control.setting.set( value ); 1034 event.preventDefault(); 1035 } 1036 }); 1037 1038 if ( this.tabs.uploaded ) { 1039 this.tabs.uploaded.target = this.library.find('.uploaded-target'); 1040 if ( ! this.tabs.uploaded.panel.find('.thumbnail').length ) 1041 this.tabs.uploaded.both.addClass('hidden'); 1042 } 1043 1044 // Select a tab 1045 panels.each( function() { 1046 var tab = control.tabs[ $(this).data('customizeTab') ]; 1047 1048 // Select the first visible tab. 1049 if ( ! tab.link.hasClass('hidden') ) { 1050 control.selected = tab; 1051 tab.both.addClass('library-selected'); 1052 return false; 1053 } 1054 }); 1055 1056 this.dropdownInit(); 1057 }, 1058 success: function( attachment ) { 1059 api.UploadControl.prototype.success.call( this, attachment ); 1060 1061 // Add the uploaded image to the uploaded tab. 1062 if ( this.tabs.uploaded && this.tabs.uploaded.target.length ) { 1063 this.tabs.uploaded.both.removeClass('hidden'); 1064 1065 // @todo: Do NOT store this on the attachment model. That is bad. 1066 attachment.element = $( '<a href="#" class="thumbnail"></a>' ) 1067 .data( 'customizeImageValue', attachment.get('url') ) 1068 .append( '<img src="' + attachment.get('url')+ '" />' ) 1069 .appendTo( this.tabs.uploaded.target ); 1070 } 1071 }, 1072 thumbnailSrc: function( to ) { 1073 if ( /^(https?:)?\/\//.test( to ) ) 1074 this.thumbnail.prop( 'src', to ).show(); 1075 else 1076 this.thumbnail.hide(); 1077 } 1035 /** 1036 * A control for uploading images. 1037 * 1038 * This control no longer needs to do anything more 1039 * than what the upload control does in JS. 1040 * 1041 * @class 1042 * @augments wp.customize.UploadControl 1043 * @augments wp.customize.Control 1044 * @augments wp.customize.Class 1045 */ 1046 api.ImageControl = api.UploadControl.extend({ 1047 // @deprecated 1048 thumbnailSrc: function( to ) {} 1078 1049 }); 1079 1050 1080 1051 /** 1081 * @c onstructor1052 * @class 1082 1053 * @augments wp.customize.Control 1083 1054 * @augments wp.customize.Class 1084 1055 */ … … 1225 1196 this.frame.open(); 1226 1197 }, 1227 1198 1199 /** 1200 * After an image is selected in the media modal, 1201 * switch to the cropper state. 1202 */ 1228 1203 onSelect: function() { 1229 1204 this.frame.setState('cropper'); 1230 1205 }, 1206 1207 /** 1208 * After the image has been cropped, apply the cropped image data to the setting. 1209 * 1210 * @param {object} croppedImage Cropped attachment data. 1211 */ 1231 1212 onCropped: function(croppedImage) { 1232 1213 var url = croppedImage.post_content, 1233 1214 attachmentId = croppedImage.attachment_id, … … 1235 1216 h = croppedImage.height; 1236 1217 this.setImageFromURL(url, attachmentId, w, h); 1237 1218 }, 1219 1220 /** 1221 * If cropping was skipped, apply the image data directly to the setting. 1222 * 1223 * @param {object} selection 1224 */ 1238 1225 onSkippedCrop: function(selection) { 1239 1226 var url = selection.get('url'), 1240 1227 w = selection.get('width'), … … 1301 1288 api.panel = new api.Values({ defaultConstructor: api.Panel }); 1302 1289 1303 1290 /** 1304 * @c onstructor1291 * @class 1305 1292 * @augments wp.customize.Messenger 1306 1293 * @augments wp.customize.Class 1307 1294 * @mixes wp.customize.Events … … 1500 1487 }()); 1501 1488 1502 1489 /** 1503 * @c onstructor1490 * @class 1504 1491 * @augments wp.customize.Messenger 1505 1492 * @augments wp.customize.Class 1506 1493 * @mixes wp.customize.Events -
src/wp-includes/class-wp-customize-control.php
637 637 * @since 3.4.0 638 638 */ 639 639 class WP_Customize_Upload_Control extends WP_Customize_Control { 640 public $type = 'upload'; 641 public $removed = ''; 642 public $context; 643 public $extensions = array(); 640 public $type = 'upload'; 641 public $mime_type = ''; 642 public $button_labels = array(); 643 public $removed = ''; // unused 644 public $context; // unused 645 public $extensions = array(); // unused 644 646 645 647 /** 648 * Constructor. 649 * 650 * @since 4.1.0 651 * @uses WP_Customize_Control::__construct() 652 * 653 * @param WP_Customize_Manager $manager 654 */ 655 public function __construct( $manager, $id, $args = array() ) { 656 parent::__construct( $manager, $id, $args ); 657 658 $this->button_labels = array( 659 'select' => __( 'Select File' ), 660 'change' => __( 'Change File' ), 661 'default' => __( 'Default' ), 662 'remove' => __( 'Remove' ), 663 'placeholder' => __( 'No file selected' ), 664 'frame_title' => __( 'Select File' ), 665 'frame_button' => __( 'Choose File' ), 666 ); 667 } 668 669 /** 646 670 * Enqueue control related scripts/styles. 647 671 * 648 672 * @since 3.4.0 649 673 */ 650 674 public function enqueue() { 651 wp_enqueue_ script( 'wp-plupload');675 wp_enqueue_media(); 652 676 } 653 677 654 678 /** … … 659 683 */ 660 684 public function to_json() { 661 685 parent::to_json(); 686 $this->json['mime_type'] = $this->mime_type; 687 $this->json['button_labels'] = $this->button_labels; 662 688 663 $this->json['removed'] = $this->removed; 689 if ( is_object( $this->setting ) ) { 690 if ( $this->setting->default ) { 691 // Fake an attachment model - needs all fields used by template. 692 $type = in_array( substr( $this->setting->default, -3 ), array( 'jpg', 'png', 'gif', 'bmp' ) ) ? 'image' : 'document'; 693 $default_attachment = array( 694 'id' => 1, 695 'url' => $this->setting->default, 696 'type' => $type, 697 'sizes' => array( 698 'full' => array( 'url' => $this->setting->default ), 699 ), 700 'icon' => wp_mime_type_icon( $type ), 701 'title' => basename( $this->setting->default ), 702 ); 703 $this->json['defaultAttachment'] = $default_attachment; 704 } 664 705 665 if ( $this->context ) 666 $this->json['context'] = $this->context; 667 668 if ( $this->extensions ) 669 $this->json['extensions'] = implode( ',', $this->extensions ); 706 // Get the attachment model for the existing file. 707 if ( $this->value() ) { 708 $attachment_id = attachment_url_to_postid( $this->value() ); 709 if ( $attachment_id ) { 710 $this->json['attachment'] = wp_prepare_attachment_for_js( $attachment_id); 711 } 712 } else if ( $this->setting->default ) { 713 // Set the default as the attachment. 714 $this->json['attachment'] = $default_attachment; 715 } 716 } 670 717 } 671 718 672 719 /** 673 * Render the control's content.720 * Don't render any content for this control from PHP. 674 721 * 722 * @see WP_Customize_Upload_Control::content_template() 675 723 * @since 3.4.0 676 724 */ 677 public function render_content() { 725 public function render_content() {} 726 727 /** 728 * Render a JS template for the content of the upload control. 729 * 730 * @since 4.1.0 731 */ 732 public function content_template() { 678 733 ?> 679 <label> 680 <?php if ( ! empty( $this->label ) ) : ?> 681 <span class="customize-control-title"><?php echo esc_html( $this->label ); ?></span> 682 <?php endif; 683 if ( ! empty( $this->description ) ) : ?> 684 <span class="description customize-control-description"><?php echo $this->description; ?></span> 685 <?php endif; ?> 686 <div> 687 <a href="#" class="button-secondary upload"><?php _e( 'Upload' ); ?></a> 688 <a href="#" class="remove"><?php _e( 'Remove' ); ?></a> 734 <label for="{{ data.settings.default }}-button"> 735 <# if ( data.label ) { #> 736 <span class="customize-control-title">{{ data.label }}</span> 737 <# } #> 738 <# if ( data.description ) { #> 739 <span class="description customize-control-description">{{ data.description }}</span> 740 <# } #> 741 </label> 742 743 <# // Ensure that the default attachment is used if it exists. 744 if ( _.isEmpty( data.attachment ) && data.defaultAttachment ) { 745 data.attachment = data.defaultAttachment; 746 } 747 748 if ( data.attachment && data.attachment.id ) { #> 749 <div class="attachment-media-view {{ data.attachment.orientation }}"> 750 <div class="thumbnail thumbnail-{{ data.attachment.type }}"> 751 <# if ( 'image' === data.attachment.type && data.attachment.sizes && data.attachment.sizes.medium ) { #> 752 <img class="attachment-thumb" src="{{ data.attachment.sizes.medium.url }}" draggable="false" /> 753 <# } else if ( 'image' === data.attachment.type && data.attachment.sizes && data.attachment.sizes.full ) { #> 754 <img class="attachment-thumb" src="{{ data.attachment.sizes.full.url }}" draggable="false" /> 755 <# } else if ( -1 === jQuery.inArray( data.attachment.type, [ 'audio', 'video' ] ) ) { #> 756 <img class="attachment-thumb type-icon" src="{{ data.attachment.icon }}" class="icon" draggable="false" /> 757 <p class="attachment-title">{{ data.attachment.title }}</p> 758 <# } #> 759 760 <# if ( 'audio' === data.attachment.type ) { #> 761 <div class="wp-media-wrapper"> 762 <p class="attachment-title">{{ data.attachment.title }}</p> 763 <audio style="visibility: hidden" controls class="wp-audio-shortcode" width="100%" preload="none"> 764 <source type="{{ data.attachment.mime }}" src="{{ data.attachment.url }}"/> 765 </audio> 766 </div> 767 <# } else if ( 'video' === data.attachment.type ) { 768 var w_rule = h_rule = ''; 769 if ( data.attachment.width ) { 770 w_rule = 'width: ' + data.attachment.width + 'px;'; 771 } else if ( wp.media.view.settings.contentWidth ) { 772 w_rule = 'width: ' + wp.media.view.settings.contentWidth + 'px;'; 773 } 774 if ( data.attachment.height ) { 775 h_rule = 'height: ' + data.attachment.height + 'px;'; 776 } 777 #> 778 <div style="{{ w_rule }}{{ h_rule }}" class="wp-media-wrapper wp-video"> 779 <video controls="controls" class="wp-video-shortcode" preload="metadata" 780 <# if ( data.attachment.width ) { #>width="{{ data.attachment.width }}"<# } #> 781 <# if ( data.attachment.height ) { #>height="{{ data.attachment.height }}"<# } #> 782 <# if ( data.attachment.image && data.attachment.image.src !== data.attachment.icon ) { #>poster="{{ data.attachment.image.src }}"<# } #>> 783 <source type="{{ data.attachment.mime }}" src="{{ data.attachment.url }}"/> 784 </video> 785 </div> 786 <# } #> 787 </div> 689 788 </div> 690 </label> 789 <a class="button upload-button" id="{{ data.settings.default }}-button" href="#"><?php echo $this->button_labels['change']; ?></a> 790 <# if ( data.defaultAttachment && data.defaultAttachment.id !== data.attachment.id ) { #> 791 <a class="default-button remove-button" href="#"><?php echo $this->button_labels['default']; ?></a> 792 <# } else { #> 793 <a class="remove-button" href="#"><?php echo $this->button_labels['remove']; ?></a> 794 <# } #> 795 <# } else { #> 796 <p class="placeholder-text"><?php echo $this->button_labels['placeholder']; ?></p> 797 <a class="button upload-button" id="{{ data.settings.default }}-button" href="#"><?php echo $this->button_labels['select']; ?></a> 798 <# if ( ! data.defaultAttachment ) { #> 799 <a class="default-button remove-button" href="#"><?php echo $this->button_labels['default']; ?></a> 800 <# } #> 801 <# } #> 691 802 <?php 692 803 } 693 804 } … … 701 812 */ 702 813 class WP_Customize_Image_Control extends WP_Customize_Upload_Control { 703 814 public $type = 'image'; 704 public $get_url; 705 public $statuses; 706 public $extensions = array( 'jpg', 'jpeg', 'gif', 'png' ); 815 public $mime_type = 'image'; 707 816 708 protected $tabs = array();709 710 817 /** 711 818 * Constructor. 712 819 * 713 * @since 3.4.0820 * @since 4.1.0 714 821 * @uses WP_Customize_Upload_Control::__construct() 715 822 * 716 823 * @param WP_Customize_Manager $manager 717 * @param string $id718 * @param array $args719 824 */ 720 public function __construct( $manager, $id, $args ) { 721 $this->statuses = array( '' => __('No Image') ); 722 825 public function __construct( $manager, $id, $args = array() ) { 723 826 parent::__construct( $manager, $id, $args ); 724 827 725 $this->add_tab( 'upload-new', __('Upload New'), array( $this, 'tab_upload_new' ) ); 726 $this->add_tab( 'uploaded', __('Uploaded'), array( $this, 'tab_uploaded' ) ); 727 728 // Early priority to occur before $this->manager->prepare_controls(); 729 add_action( 'customize_controls_init', array( $this, 'prepare_control' ), 5 ); 828 $this->button_labels = array( 829 'select' => __( 'Select Image' ), 830 'change' => __( 'Change Image' ), 831 'remove' => __( 'Remove' ), 832 'default' => __( 'Default' ), 833 'placeholder' => __( 'No image selected' ), 834 'frame_title' => __( 'Select Image' ), 835 'frame_button' => __( 'Choose Image' ), 836 ); 730 837 } 731 838 732 839 /** 733 * Prepares the control.734 *735 * If no tabs exist, removes the control from the manager.736 *737 840 * @since 3.4.2 841 * @deprecated 4.1.0 738 842 */ 739 public function prepare_control() { 740 if ( ! $this->tabs ) 741 $this->manager->remove_control( $this->id ); 742 } 843 public function prepare_control() {} 743 844 744 845 /** 745 * Refresh the parameters passed to the JavaScript via JSON.746 *747 846 * @since 3.4.0 748 * @uses WP_Customize_Upload_Control::to_json() 749 */ 750 public function to_json() { 751 parent::to_json(); 752 $this->json['statuses'] = $this->statuses; 753 } 754 755 /** 756 * Render the control's content. 847 * @deprecated 4.1.0 757 848 * 758 * @since 3.4.0759 */760 public function render_content() {761 $src = $this->value();762 if ( isset( $this->get_url ) )763 $src = call_user_func( $this->get_url, $src );764 765 ?>766 <div class="customize-image-picker">767 <?php if ( ! empty( $this->label ) ) : ?>768 <span class="customize-control-title"><?php echo esc_html( $this->label ); ?></span>769 <?php endif;770 if ( ! empty( $this->description ) ) : ?>771 <span class="description customize-control-description"><?php echo $this->description; ?></span>772 <?php endif; ?>773 774 <div class="customize-control-content">775 <div class="dropdown preview-thumbnail" tabindex="0">776 <div class="dropdown-content">777 <?php if ( empty( $src ) ): ?>778 <img style="display:none;" />779 <?php else: ?>780 <img src="<?php echo esc_url( set_url_scheme( $src ) ); ?>" />781 <?php endif; ?>782 <div class="dropdown-status"></div>783 </div>784 <div class="dropdown-arrow"></div>785 </div>786 </div>787 788 <div class="library">789 <ul>790 <?php foreach ( $this->tabs as $id => $tab ): ?>791 <li data-customize-tab='<?php echo esc_attr( $id ); ?>' tabindex='0'>792 <?php echo esc_html( $tab['label'] ); ?>793 </li>794 <?php endforeach; ?>795 </ul>796 <?php foreach ( $this->tabs as $id => $tab ): ?>797 <div class="library-content" data-customize-tab='<?php echo esc_attr( $id ); ?>'>798 <?php call_user_func( $tab['callback'] ); ?>799 </div>800 <?php endforeach; ?>801 </div>802 803 <div class="actions">804 <a href="#" class="remove"><?php _e( 'Remove Image' ); ?></a>805 </div>806 </div>807 <?php808 }809 810 /**811 * Add a tab to the control.812 *813 * @since 3.4.0814 *815 849 * @param string $id 816 850 * @param string $label 817 851 * @param mixed $callback 818 852 */ 819 public function add_tab( $id, $label, $callback ) { 820 $this->tabs[ $id ] = array( 821 'label' => $label, 822 'callback' => $callback, 823 ); 824 } 853 public function add_tab( $id, $label, $callback ) {} 825 854 826 855 /** 827 * Remove a tab from the control.828 *829 856 * @since 3.4.0 857 * @deprecated 4.1.0 830 858 * 831 859 * @param string $id 832 860 */ 833 public function remove_tab( $id ) { 834 unset( $this->tabs[ $id ] ); 835 } 861 public function remove_tab( $id ) {} 836 862 837 863 /** 838 864 * @since 3.4.0 839 */ 840 public function tab_upload_new() { 841 if ( ! _device_can_upload() ) { 842 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>'; 843 } else { 844 ?> 845 <div class="upload-dropzone"> 846 <?php _e('Drop a file here or <a href="#" class="upload">select a file</a>.'); ?> 847 </div> 848 <div class="upload-fallback"> 849 <span class="button-secondary"><?php _e('Select File'); ?></span> 850 </div> 851 <?php 852 } 853 } 854 855 /** 856 * @since 3.4.0 857 */ 858 public function tab_uploaded() { 859 ?> 860 <div class="uploaded-target"></div> 861 <?php 862 } 863 864 /** 865 * @since 3.4.0 865 * @deprecated 4.1.0 866 866 * 867 867 * @param string $url 868 868 * @param string $thumbnail_url 869 869 */ 870 public function print_tab_image( $url, $thumbnail_url = null ) { 871 $url = set_url_scheme( $url ); 872 $thumbnail_url = ( $thumbnail_url ) ? set_url_scheme( $thumbnail_url ) : $url; 873 ?> 874 <a href="#" class="thumbnail" data-customize-image-value="<?php echo esc_url( $url ); ?>"> 875 <img src="<?php echo esc_url( $thumbnail_url ); ?>" /> 876 </a> 877 <?php 878 } 870 public function print_tab_image( $url, $thumbnail_url = null ) {} 879 871 } 880 872 881 873 /** … … 899 891 parent::__construct( $manager, 'background_image', array( 900 892 'label' => __( 'Background Image' ), 901 893 'section' => 'background_image', 902 'context' => 'custom-background',903 'get_url' => 'get_background_image',904 894 ) ); 905 906 if ( $this->setting->default )907 $this->add_tab( 'default', __('Default'), array( $this, 'tab_default_background' ) );908 895 } 909 910 /**911 * @since 3.4.0912 */913 public function tab_uploaded() {914 $backgrounds = get_posts( array(915 'post_type' => 'attachment',916 'meta_key' => '_wp_attachment_is_custom_background',917 'meta_value' => $this->manager->get_stylesheet(),918 'orderby' => 'none',919 'nopaging' => true,920 ) );921 922 ?><div class="uploaded-target"></div><?php923 924 if ( empty( $backgrounds ) )925 return;926 927 foreach ( (array) $backgrounds as $background )928 $this->print_tab_image( esc_url_raw( $background->guid ) );929 }930 931 /**932 * @since 3.4.0933 * @uses WP_Customize_Image_Control::print_tab_image()934 */935 public function tab_default_background() {936 $this->print_tab_image( $this->setting->default );937 }938 896 } 939 897 940 898 class WP_Customize_Header_Image_Control extends WP_Customize_Image_Control { -
src/wp-includes/class-wp-customize-manager.php
965 965 966 966 /* Control Types (custom control classes) */ 967 967 $this->register_control_type( 'WP_Customize_Color_Control' ); 968 $this->register_control_type( 'WP_Customize_Upload_Control' ); 969 $this->register_control_type( 'WP_Customize_Image_Control' ); 968 970 969 971 /* Site Title & Tagline */ 970 972