WordPress 4.0
[autoinstalls/wordpress.git] / wp-includes / class-wp-customize-control.php
1 <?php
2 /**
3  * Customize Control Class
4  *
5  * @package WordPress
6  * @subpackage Customize
7  * @since 3.4.0
8  */
9 class WP_Customize_Control {
10         /**
11          * @access public
12          * @var WP_Customize_Manager
13          */
14         public $manager;
15
16         /**
17          * @access public
18          * @var string
19          */
20         public $id;
21
22         /**
23          * All settings tied to the control.
24          *
25          * @access public
26          * @var array
27          */
28         public $settings;
29
30         /**
31          * The primary setting for the control (if there is one).
32          *
33          * @access public
34          * @var string
35          */
36         public $setting = 'default';
37
38         /**
39          * @access public
40          * @var int
41          */
42         public $priority = 10;
43
44         /**
45          * @access public
46          * @var string
47          */
48         public $section = '';
49
50         /**
51          * @access public
52          * @var string
53          */
54         public $label = '';
55
56         /**
57          * @access public
58          * @var string
59          */
60         public $description = '';
61
62         /**
63          * @todo: Remove choices
64          *
65          * @access public
66          * @var array
67          */
68         public $choices = array();
69
70         /**
71          * @access public
72          * @var array
73          */
74         public $input_attrs = array();
75
76         /**
77          * @access public
78          * @var array
79          */
80         public $json = array();
81
82         /**
83          * @access public
84          * @var string
85          */
86         public $type = 'text';
87
88         /**
89          * Callback.
90          *
91          * @since 4.0.0
92          * @access public
93          *
94          * @see WP_Customize_Control::active()
95          *
96          * @var callable Callback is called with one argument, the instance of
97          *               WP_Customize_Control, and returns bool to indicate whether
98          *               the control is active (such as it relates to the URL
99          *               currently being previewed).
100          */
101         public $active_callback = '';
102
103         /**
104          * Constructor.
105          *
106          * Supplied $args override class property defaults.
107          *
108          * If $args['settings'] is not defined, use the $id as the setting ID.
109          *
110          * @since 3.4.0
111          *
112          * @param WP_Customize_Manager $manager
113          * @param string $id
114          * @param array $args
115          */
116         public function __construct( $manager, $id, $args = array() ) {
117                 $keys = array_keys( get_object_vars( $this ) );
118                 foreach ( $keys as $key ) {
119                         if ( isset( $args[ $key ] ) ) {
120                                 $this->$key = $args[ $key ];
121                         }
122                 }
123
124                 $this->manager = $manager;
125                 $this->id = $id;
126                 if ( empty( $this->active_callback ) ) {
127                         $this->active_callback = array( $this, 'active_callback' );
128                 }
129
130                 // Process settings.
131                 if ( empty( $this->settings ) ) {
132                         $this->settings = $id;
133                 }
134
135                 $settings = array();
136                 if ( is_array( $this->settings ) ) {
137                         foreach ( $this->settings as $key => $setting ) {
138                                 $settings[ $key ] = $this->manager->get_setting( $setting );
139                         }
140                 } else {
141                         $this->setting = $this->manager->get_setting( $this->settings );
142                         $settings['default'] = $this->setting;
143                 }
144                 $this->settings = $settings;
145         }
146
147         /**
148          * Enqueue control related scripts/styles.
149          *
150          * @since 3.4.0
151          */
152         public function enqueue() {}
153
154         /**
155          * Check whether control is active to current customizer preview.
156          *
157          * @since 4.0.0
158          * @access public
159          *
160          * @return bool Whether the control is active to the current preview.
161          */
162         public final function active() {
163                 $control = $this;
164                 $active = call_user_func( $this->active_callback, $this );
165
166                 /**
167                  * Filter response of WP_Customize_Control::active().
168                  *
169                  * @since 4.0.0
170                  *
171                  * @param bool                 $active  Whether the Customizer control is active.
172                  * @param WP_Customize_Control $control WP_Customize_Control instance.
173                  */
174                 $active = apply_filters( 'customize_control_active', $active, $control );
175
176                 return $active;
177         }
178
179         /**
180          * Default callback used when invoking WP_Customize_Control::active().
181          *
182          * Subclasses can override this with their specific logic, or they may
183          * provide an 'active_callback' argument to the constructor.
184          *
185          * @since 4.0.0
186          * @access public
187          *
188          * @return bool Always true.
189          */
190         public function active_callback() {
191                 return true;
192         }
193
194         /**
195          * Fetch a setting's value.
196          * Grabs the main setting by default.
197          *
198          * @since 3.4.0
199          *
200          * @param string $setting_key
201          * @return mixed The requested setting's value, if the setting exists.
202          */
203         public final function value( $setting_key = 'default' ) {
204                 if ( isset( $this->settings[ $setting_key ] ) ) {
205                         return $this->settings[ $setting_key ]->value();
206                 }
207         }
208
209         /**
210          * Refresh the parameters passed to the JavaScript via JSON.
211          *
212          * @since 3.4.0
213          */
214         public function to_json() {
215                 $this->json['settings'] = array();
216                 foreach ( $this->settings as $key => $setting ) {
217                         $this->json['settings'][ $key ] = $setting->id;
218                 }
219
220                 $this->json['type'] = $this->type;
221                 $this->json['active'] = $this->active();
222         }
223
224         /**
225          * Check if the theme supports the control and check user capabilities.
226          *
227          * @since 3.4.0
228          *
229          * @return bool False if theme doesn't support the control or user doesn't have the required permissions, otherwise true.
230          */
231         public final function check_capabilities() {
232                 foreach ( $this->settings as $setting ) {
233                         if ( ! $setting->check_capabilities() )
234                                 return false;
235                 }
236
237                 $section = $this->manager->get_section( $this->section );
238                 if ( isset( $section ) && ! $section->check_capabilities() )
239                         return false;
240
241                 return true;
242         }
243
244         /**
245          * Check capabilities and render the control.
246          *
247          * @since 3.4.0
248          * @uses WP_Customize_Control::render()
249          */
250         public final function maybe_render() {
251                 if ( ! $this->check_capabilities() )
252                         return;
253
254                 /**
255                  * Fires just before the current Customizer control is rendered.
256                  *
257                  * @since 3.4.0
258                  *
259                  * @param WP_Customize_Control $this WP_Customize_Control instance.
260                  */
261                 do_action( 'customize_render_control', $this );
262
263                 /**
264                  * Fires just before a specific Customizer control is rendered.
265                  *
266                  * The dynamic portion of the hook name, $this->id, refers to
267                  * the control ID.
268                  *
269                  * @since 3.4.0
270                  *
271                  * @param WP_Customize_Control $this WP_Customize_Control instance.
272                  */
273                 do_action( 'customize_render_control_' . $this->id, $this );
274
275                 $this->render();
276         }
277
278         /**
279          * Renders the control wrapper and calls $this->render_content() for the internals.
280          *
281          * @since 3.4.0
282          */
283         protected function render() {
284                 $id    = 'customize-control-' . str_replace( '[', '-', str_replace( ']', '', $this->id ) );
285                 $class = 'customize-control customize-control-' . $this->type;
286
287                 ?><li id="<?php echo esc_attr( $id ); ?>" class="<?php echo esc_attr( $class ); ?>">
288                         <?php $this->render_content(); ?>
289                 </li><?php
290         }
291
292         /**
293          * Get the data link attribute for a setting.
294          *
295          * @since 3.4.0
296          *
297          * @param string $setting_key
298          * @return string Data link parameter, if $setting_key is a valid setting, empty string otherwise.
299          */
300         public function get_link( $setting_key = 'default' ) {
301                 if ( ! isset( $this->settings[ $setting_key ] ) )
302                         return '';
303
304                 return 'data-customize-setting-link="' . esc_attr( $this->settings[ $setting_key ]->id ) . '"';
305         }
306
307         /**
308          * Render the data link attribute for the control's input element.
309          *
310          * @since 3.4.0
311          * @uses WP_Customize_Control::get_link()
312          *
313          * @param string $setting_key
314          */
315         public function link( $setting_key = 'default' ) {
316                 echo $this->get_link( $setting_key );
317         }
318
319         /**
320          * Render the custom attributes for the control's input element.
321          *
322          * @since 4.0.0
323          * @access public
324          */
325         public function input_attrs() {
326                 foreach( $this->input_attrs as $attr => $value ) {
327                         echo $attr . '="' . esc_attr( $value ) . '" ';
328                 }
329         }
330
331         /**
332          * Render the control's content.
333          *
334          * Allows the content to be overriden without having to rewrite the wrapper in $this->render().
335          *
336          * Supports basic input types `text`, `checkbox`, `textarea`, `radio`, `select` and `dropdown-pages`.
337          * Additional input types such as `email`, `url`, `number`, `hidden` and `date` are supported implicitly.
338          *
339          * @since 3.4.0
340          */
341         protected function render_content() {
342                 switch( $this->type ) {
343                         case 'checkbox':
344                                 ?>
345                                 <label>
346                                         <input type="checkbox" value="<?php echo esc_attr( $this->value() ); ?>" <?php $this->link(); checked( $this->value() ); ?> />
347                                         <?php echo esc_html( $this->label ); ?>
348                                         <?php if ( ! empty( $this->description ) ) : ?>
349                                                 <span class="description customize-control-description"><?php echo $this->description; ?></span>
350                                         <?php endif; ?>
351                                 </label>
352                                 <?php
353                                 break;
354                         case 'radio':
355                                 if ( empty( $this->choices ) )
356                                         return;
357
358                                 $name = '_customize-radio-' . $this->id;
359
360                                 if ( ! empty( $this->label ) ) : ?>
361                                         <span class="customize-control-title"><?php echo esc_html( $this->label ); ?></span>
362                                 <?php endif;
363                                 if ( ! empty( $this->description ) ) : ?>
364                                         <span class="description customize-control-description"><?php echo $this->description ; ?></span>
365                                 <?php endif;
366
367                                 foreach ( $this->choices as $value => $label ) :
368                                         ?>
369                                         <label>
370                                                 <input type="radio" value="<?php echo esc_attr( $value ); ?>" name="<?php echo esc_attr( $name ); ?>" <?php $this->link(); checked( $this->value(), $value ); ?> />
371                                                 <?php echo esc_html( $label ); ?><br/>
372                                         </label>
373                                         <?php
374                                 endforeach;
375                                 break;
376                         case 'select':
377                                 if ( empty( $this->choices ) )
378                                         return;
379
380                                 ?>
381                                 <label>
382                                         <?php if ( ! empty( $this->label ) ) : ?>
383                                                 <span class="customize-control-title"><?php echo esc_html( $this->label ); ?></span>
384                                         <?php endif;
385                                         if ( ! empty( $this->description ) ) : ?>
386                                                 <span class="description customize-control-description"><?php echo $this->description; ?></span>
387                                         <?php endif; ?>
388
389                                         <select <?php $this->link(); ?>>
390                                                 <?php
391                                                 foreach ( $this->choices as $value => $label )
392                                                         echo '<option value="' . esc_attr( $value ) . '"' . selected( $this->value(), $value, false ) . '>' . $label . '</option>';
393                                                 ?>
394                                         </select>
395                                 </label>
396                                 <?php
397                                 break;
398                         case 'textarea':
399                                 ?>
400                                 <label>
401                                         <?php if ( ! empty( $this->label ) ) : ?>
402                                                 <span class="customize-control-title"><?php echo esc_html( $this->label ); ?></span>
403                                         <?php endif;
404                                         if ( ! empty( $this->description ) ) : ?>
405                                                 <span class="description customize-control-description"><?php echo $this->description; ?></span>
406                                         <?php endif; ?>
407                                         <textarea rows="5" <?php $this->link(); ?>><?php echo esc_textarea( $this->value() ); ?></textarea>
408                                 </label>
409                                 <?php
410                                 break;
411                         case 'dropdown-pages':
412                                 $dropdown = wp_dropdown_pages(
413                                         array(
414                                                 'name'              => '_customize-dropdown-pages-' . $this->id,
415                                                 'echo'              => 0,
416                                                 'show_option_none'  => __( '&mdash; Select &mdash;' ),
417                                                 'option_none_value' => '0',
418                                                 'selected'          => $this->value(),
419                                         )
420                                 );
421
422                                 // Hackily add in the data link parameter.
423                                 $dropdown = str_replace( '<select', '<select ' . $this->get_link(), $dropdown );
424
425                                 printf(
426                                         '<label class="customize-control-select"><span class="customize-control-title">%s</span> %s</label>',
427                                         $this->label,
428                                         $dropdown
429                                 );
430                                 break;
431                         default:
432                                 ?>
433                                 <label>
434                                         <?php if ( ! empty( $this->label ) ) : ?>
435                                                 <span class="customize-control-title"><?php echo esc_html( $this->label ); ?></span>
436                                         <?php endif;
437                                         if ( ! empty( $this->description ) ) : ?>
438                                                 <span class="description customize-control-description"><?php echo $this->description; ?></span>
439                                         <?php endif; ?>
440                                         <input type="<?php echo esc_attr( $this->type ); ?>" <?php $this->input_attrs(); ?> value="<?php echo esc_attr( $this->value() ); ?>" <?php $this->link(); ?> />
441                                 </label>
442                                 <?php
443                                 break;
444                 }
445         }
446 }
447
448 /**
449  * Customize Color Control Class
450  *
451  * @package WordPress
452  * @subpackage Customize
453  * @since 3.4.0
454  */
455 class WP_Customize_Color_Control extends WP_Customize_Control {
456         /**
457          * @access public
458          * @var string
459          */
460         public $type = 'color';
461
462         /**
463          * @access public
464          * @var array
465          */
466         public $statuses;
467
468         /**
469          * Constructor.
470          *
471          * @since 3.4.0
472          * @uses WP_Customize_Control::__construct()
473          *
474          * @param WP_Customize_Manager $manager
475          * @param string $id
476          * @param array $args
477          */
478         public function __construct( $manager, $id, $args = array() ) {
479                 $this->statuses = array( '' => __('Default') );
480                 parent::__construct( $manager, $id, $args );
481         }
482
483         /**
484          * Enqueue scripts/styles for the color picker.
485          *
486          * @since 3.4.0
487          */
488         public function enqueue() {
489                 wp_enqueue_script( 'wp-color-picker' );
490                 wp_enqueue_style( 'wp-color-picker' );
491         }
492
493         /**
494          * Refresh the parameters passed to the JavaScript via JSON.
495          *
496          * @since 3.4.0
497          * @uses WP_Customize_Control::to_json()
498          */
499         public function to_json() {
500                 parent::to_json();
501                 $this->json['statuses'] = $this->statuses;
502         }
503
504         /**
505          * Render the control's content.
506          *
507          * @since 3.4.0
508          */
509         public function render_content() {
510                 $this_default = $this->setting->default;
511                 $default_attr = '';
512                 if ( $this_default ) {
513                         if ( false === strpos( $this_default, '#' ) )
514                                 $this_default = '#' . $this_default;
515                         $default_attr = ' data-default-color="' . esc_attr( $this_default ) . '"';
516                 }
517                 // The input's value gets set by JS. Don't fill it.
518                 ?>
519                 <label>
520                         <?php if ( ! empty( $this->label ) ) : ?>
521                                 <span class="customize-control-title"><?php echo esc_html( $this->label ); ?></span>
522                         <?php endif;
523                         if ( ! empty( $this->description ) ) : ?>
524                                 <span class="description customize-control-description"><?php echo $this->description; ?></span>
525                         <?php endif; ?>
526
527                         <div class="customize-control-content">
528                                 <input class="color-picker-hex" type="text" maxlength="7" placeholder="<?php esc_attr_e( 'Hex Value' ); ?>"<?php echo $default_attr; ?> />
529                         </div>
530                 </label>
531                 <?php
532         }
533 }
534
535 /**
536  * Customize Upload Control Class
537  *
538  * @package WordPress
539  * @subpackage Customize
540  * @since 3.4.0
541  */
542 class WP_Customize_Upload_Control extends WP_Customize_Control {
543         public $type    = 'upload';
544         public $removed = '';
545         public $context;
546         public $extensions = array();
547
548         /**
549          * Enqueue control related scripts/styles.
550          *
551          * @since 3.4.0
552          */
553         public function enqueue() {
554                 wp_enqueue_script( 'wp-plupload' );
555         }
556
557         /**
558          * Refresh the parameters passed to the JavaScript via JSON.
559          *
560          * @since 3.4.0
561          * @uses WP_Customize_Control::to_json()
562          */
563         public function to_json() {
564                 parent::to_json();
565
566                 $this->json['removed'] = $this->removed;
567
568                 if ( $this->context )
569                         $this->json['context'] = $this->context;
570
571                 if ( $this->extensions )
572                         $this->json['extensions'] = implode( ',', $this->extensions );
573         }
574
575         /**
576          * Render the control's content.
577          *
578          * @since 3.4.0
579          */
580         public function render_content() {
581                 ?>
582                 <label>
583                         <?php if ( ! empty( $this->label ) ) : ?>
584                                 <span class="customize-control-title"><?php echo esc_html( $this->label ); ?></span>
585                         <?php endif;
586                         if ( ! empty( $this->description ) ) : ?>
587                                 <span class="description customize-control-description"><?php echo $this->description; ?></span>
588                         <?php endif; ?>
589                         <div>
590                                 <a href="#" class="button-secondary upload"><?php _e( 'Upload' ); ?></a>
591                                 <a href="#" class="remove"><?php _e( 'Remove' ); ?></a>
592                         </div>
593                 </label>
594                 <?php
595         }
596 }
597
598 /**
599  * Customize Image Control Class
600  *
601  * @package WordPress
602  * @subpackage Customize
603  * @since 3.4.0
604  */
605 class WP_Customize_Image_Control extends WP_Customize_Upload_Control {
606         public $type = 'image';
607         public $get_url;
608         public $statuses;
609         public $extensions = array( 'jpg', 'jpeg', 'gif', 'png' );
610
611         protected $tabs = array();
612
613         /**
614          * Constructor.
615          *
616          * @since 3.4.0
617          * @uses WP_Customize_Upload_Control::__construct()
618          *
619          * @param WP_Customize_Manager $manager
620          * @param string $id
621          * @param array $args
622          */
623         public function __construct( $manager, $id, $args ) {
624                 $this->statuses = array( '' => __('No Image') );
625
626                 parent::__construct( $manager, $id, $args );
627
628                 $this->add_tab( 'upload-new', __('Upload New'), array( $this, 'tab_upload_new' ) );
629                 $this->add_tab( 'uploaded',   __('Uploaded'),   array( $this, 'tab_uploaded' ) );
630
631                 // Early priority to occur before $this->manager->prepare_controls();
632                 add_action( 'customize_controls_init', array( $this, 'prepare_control' ), 5 );
633         }
634
635         /**
636          * Prepares the control.
637          *
638          * If no tabs exist, removes the control from the manager.
639          *
640          * @since 3.4.2
641          */
642         public function prepare_control() {
643                 if ( ! $this->tabs )
644                         $this->manager->remove_control( $this->id );
645         }
646
647         /**
648          * Refresh the parameters passed to the JavaScript via JSON.
649          *
650          * @since 3.4.0
651          * @uses WP_Customize_Upload_Control::to_json()
652          */
653         public function to_json() {
654                 parent::to_json();
655                 $this->json['statuses'] = $this->statuses;
656         }
657
658         /**
659          * Render the control's content.
660          *
661          * @since 3.4.0
662          */
663         public function render_content() {
664                 $src = $this->value();
665                 if ( isset( $this->get_url ) )
666                         $src = call_user_func( $this->get_url, $src );
667
668                 ?>
669                 <div class="customize-image-picker">
670                         <?php if ( ! empty( $this->label ) ) : ?>
671                                 <span class="customize-control-title"><?php echo esc_html( $this->label ); ?></span>
672                         <?php endif;
673                         if ( ! empty( $this->description ) ) : ?>
674                                 <span class="description customize-control-description"><?php echo $this->description; ?></span>
675                         <?php endif; ?>
676
677                         <div class="customize-control-content">
678                                 <div class="dropdown preview-thumbnail" tabindex="0">
679                                         <div class="dropdown-content">
680                                                 <?php if ( empty( $src ) ): ?>
681                                                         <img style="display:none;" />
682                                                 <?php else: ?>
683                                                         <img src="<?php echo esc_url( set_url_scheme( $src ) ); ?>" />
684                                                 <?php endif; ?>
685                                                 <div class="dropdown-status"></div>
686                                         </div>
687                                         <div class="dropdown-arrow"></div>
688                                 </div>
689                         </div>
690
691                         <div class="library">
692                                 <ul>
693                                         <?php foreach ( $this->tabs as $id => $tab ): ?>
694                                                 <li data-customize-tab='<?php echo esc_attr( $id ); ?>' tabindex='0'>
695                                                         <?php echo esc_html( $tab['label'] ); ?>
696                                                 </li>
697                                         <?php endforeach; ?>
698                                 </ul>
699                                 <?php foreach ( $this->tabs as $id => $tab ): ?>
700                                         <div class="library-content" data-customize-tab='<?php echo esc_attr( $id ); ?>'>
701                                                 <?php call_user_func( $tab['callback'] ); ?>
702                                         </div>
703                                 <?php endforeach; ?>
704                         </div>
705
706                         <div class="actions">
707                                 <a href="#" class="remove"><?php _e( 'Remove Image' ); ?></a>
708                         </div>
709                 </div>
710                 <?php
711         }
712
713         /**
714          * Add a tab to the control.
715          *
716          * @since 3.4.0
717          *
718          * @param string $id
719          * @param string $label
720          * @param mixed $callback
721          */
722         public function add_tab( $id, $label, $callback ) {
723                 $this->tabs[ $id ] = array(
724                         'label'    => $label,
725                         'callback' => $callback,
726                 );
727         }
728
729         /**
730          * Remove a tab from the control.
731          *
732          * @since 3.4.0
733          *
734          * @param string $id
735          */
736         public function remove_tab( $id ) {
737                 unset( $this->tabs[ $id ] );
738         }
739
740         /**
741          * @since 3.4.0
742          */
743         public function tab_upload_new() {
744                 if ( ! _device_can_upload() ) {
745                         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.'), 'http://apps.wordpress.org/' ) . '</p>';
746                 } else {
747                         ?>
748                         <div class="upload-dropzone">
749                                 <?php _e('Drop a file here or <a href="#" class="upload">select a file</a>.'); ?>
750                         </div>
751                         <div class="upload-fallback">
752                                 <span class="button-secondary"><?php _e('Select File'); ?></span>
753                         </div>
754                         <?php
755                 }
756         }
757
758         /**
759          * @since 3.4.0
760          */
761         public function tab_uploaded() {
762                 ?>
763                 <div class="uploaded-target"></div>
764                 <?php
765         }
766
767         /**
768          * @since 3.4.0
769          *
770          * @param string $url
771          * @param string $thumbnail_url
772          */
773         public function print_tab_image( $url, $thumbnail_url = null ) {
774                 $url = set_url_scheme( $url );
775                 $thumbnail_url = ( $thumbnail_url ) ? set_url_scheme( $thumbnail_url ) : $url;
776                 ?>
777                 <a href="#" class="thumbnail" data-customize-image-value="<?php echo esc_url( $url ); ?>">
778                         <img src="<?php echo esc_url( $thumbnail_url ); ?>" />
779                 </a>
780                 <?php
781         }
782 }
783
784 /**
785  * Customize Background Image Control Class
786  *
787  * @package WordPress
788  * @subpackage Customize
789  * @since 3.4.0
790  */
791 class WP_Customize_Background_Image_Control extends WP_Customize_Image_Control {
792
793         /**
794          * Constructor.
795          *
796          * @since 3.4.0
797          * @uses WP_Customize_Image_Control::__construct()
798          *
799          * @param WP_Customize_Manager $manager
800          */
801         public function __construct( $manager ) {
802                 parent::__construct( $manager, 'background_image', array(
803                         'label'    => __( 'Background Image' ),
804                         'section'  => 'background_image',
805                         'context'  => 'custom-background',
806                         'get_url'  => 'get_background_image',
807                 ) );
808
809                 if ( $this->setting->default )
810                         $this->add_tab( 'default',  __('Default'),  array( $this, 'tab_default_background' ) );
811         }
812
813         /**
814          * @since 3.4.0
815          */
816         public function tab_uploaded() {
817                 $backgrounds = get_posts( array(
818                         'post_type'  => 'attachment',
819                         'meta_key'   => '_wp_attachment_is_custom_background',
820                         'meta_value' => $this->manager->get_stylesheet(),
821                         'orderby'    => 'none',
822                         'nopaging'   => true,
823                 ) );
824
825                 ?><div class="uploaded-target"></div><?php
826
827                 if ( empty( $backgrounds ) )
828                         return;
829
830                 foreach ( (array) $backgrounds as $background )
831                         $this->print_tab_image( esc_url_raw( $background->guid ) );
832         }
833
834         /**
835          * @since 3.4.0
836          * @uses WP_Customize_Image_Control::print_tab_image()
837          */
838         public function tab_default_background() {
839                 $this->print_tab_image( $this->setting->default );
840         }
841 }
842
843 class WP_Customize_Header_Image_Control extends WP_Customize_Image_Control {
844         public $type = 'header';
845
846         public function __construct( $manager ) {
847                 parent::__construct( $manager, 'header_image', array(
848                         'label'    => __( 'Header Image' ),
849                         'settings' => array(
850                                 'default' => 'header_image',
851                                 'data'    => 'header_image_data',
852                         ),
853                         'section'  => 'header_image',
854                         'context'  => 'custom-header',
855                         'removed'  => 'remove-header',
856                         'get_url'  => 'get_header_image',
857                 ) );
858
859         }
860
861         public function to_json() {
862                 parent::to_json();
863         }
864
865         public function enqueue() {
866                 wp_enqueue_media();
867                 wp_enqueue_script( 'customize-views' );
868
869                 $this->prepare_control();
870
871                 wp_localize_script( 'customize-views', '_wpCustomizeHeader', array(
872                         'data' => array(
873                                 'width' => absint( get_theme_support( 'custom-header', 'width' ) ),
874                                 'height' => absint( get_theme_support( 'custom-header', 'height' ) ),
875                                 'flex-width' => absint( get_theme_support( 'custom-header', 'flex-width' ) ),
876                                 'flex-height' => absint( get_theme_support( 'custom-header', 'flex-height' ) ),
877                                 'currentImgSrc' => $this->get_current_image_src(),
878                         ),
879                         'nonces' => array(
880                                 'add' => wp_create_nonce( 'header-add' ),
881                                 'remove' => wp_create_nonce( 'header-remove' ),
882                         ),
883                         'uploads' => $this->uploaded_headers,
884                         'defaults' => $this->default_headers
885                 ) );
886
887                 parent::enqueue();
888         }
889
890         public function prepare_control() {
891                 global $custom_image_header;
892                 if ( empty( $custom_image_header ) ) {
893                         return;
894                 }
895
896                 // Process default headers and uploaded headers.
897                 $custom_image_header->process_default_headers();
898                 $this->default_headers = $custom_image_header->get_default_header_images();
899                 $this->uploaded_headers = $custom_image_header->get_uploaded_header_images();
900         }
901
902         function print_header_image_template() {
903                 ?>
904                 <script type="text/template" id="tmpl-header-choice">
905                         <# if (data.random) { #>
906                                         <button type="button" class="button display-options random">
907                                                 <span class="dashicons dashicons-randomize dice"></span>
908                                                 <# if ( data.type === 'uploaded' ) { #>
909                                                         <?php _e( 'Randomize uploaded headers' ); ?>
910                                                 <# } else if ( data.type === 'default' ) { #>
911                                                         <?php _e( 'Randomize suggested headers' ); ?>
912                                                 <# } #>
913                                         </button>
914
915                         <# } else { #>
916
917                         <# if (data.type === 'uploaded') { #>
918                                 <div class="dashicons dashicons-no close"></div>
919                         <# } #>
920
921                         <button type="button" class="choice thumbnail"
922                                 data-customize-image-value="{{{data.header.url}}}"
923                                 data-customize-header-image-data="{{JSON.stringify(data.header)}}">
924                                 <span class="screen-reader-text"><?php _e( 'Set image' ); ?></span>
925                                 <img src="{{{data.header.thumbnail_url}}}" alt="{{{data.header.alt_text || data.header.description}}}">
926                         </button>
927
928                         <# } #>
929                 </script>
930
931                 <script type="text/template" id="tmpl-header-current">
932                         <# if (data.choice) { #>
933                                 <# if (data.random) { #>
934
935                         <div class="placeholder">
936                                 <div class="inner">
937                                         <span><span class="dashicons dashicons-randomize dice"></span>
938                                         <# if ( data.type === 'uploaded' ) { #>
939                                                 <?php _e( 'Randomizing uploaded headers' ); ?>
940                                         <# } else if ( data.type === 'default' ) { #>
941                                                 <?php _e( 'Randomizing suggested headers' ); ?>
942                                         <# } #>
943                                         </span>
944                                 </div>
945                         </div>
946
947                                 <# } else { #>
948
949                         <img src="{{{data.header.thumbnail_url}}}" alt="{{{data.header.alt_text || data.header.description}}}" tabindex="0"/>
950
951                                 <# } #>
952                         <# } else { #>
953
954                         <div class="placeholder">
955                                 <div class="inner">
956                                         <span>
957                                                 <?php _e( 'No image set' ); ?>
958                                         </span>
959                                 </div>
960                         </div>
961
962                         <# } #>
963                 </script>
964                 <?php
965         }
966
967         public function get_current_image_src() {
968                 $src = $this->value();
969                 if ( isset( $this->get_url ) ) {
970                         $src = call_user_func( $this->get_url, $src );
971                         return $src;
972                 }
973                 return null;
974         }
975
976         public function render_content() {
977                 $this->print_header_image_template();
978                 $visibility = $this->get_current_image_src() ? '' : ' style="display:none" ';
979                 $width = absint( get_theme_support( 'custom-header', 'width' ) );
980                 $height = absint( get_theme_support( 'custom-header', 'height' ) );
981                 ?>
982
983
984                 <div class="customize-control-content">
985                         <p class="customizer-section-intro">
986                                 <?php
987                                 if ( $width && $height ) {
988                                         printf( __( 'While you can crop images to your liking after clicking <strong>Add new image</strong>, your theme recommends a header size of <strong>%s &times; %s</strong> pixels.' ), $width, $height );
989                                 } elseif ( $width ) {
990                                         printf( __( 'While you can crop images to your liking after clicking <strong>Add new image</strong>, your theme recommends a header width of <strong>%s</strong> pixels.' ), $width );
991                                 } else {
992                                         printf( __( 'While you can crop images to your liking after clicking <strong>Add new image</strong>, your theme recommends a header height of <strong>%s</strong> pixels.' ), $height );
993                                 }
994                                 ?>
995                         </p>
996                         <div class="current">
997                                 <span class="customize-control-title">
998                                         <?php _e( 'Current header' ); ?>
999                                 </span>
1000                                 <div class="container">
1001                                 </div>
1002                         </div>
1003                         <div class="actions">
1004                                 <?php /* translators: Hide as in hide header image via the Customizer */ ?>
1005                                 <button type="button"<?php echo $visibility ?> class="button remove"><?php _ex( 'Hide image', 'custom header' ); ?></button>
1006                                 <?php /* translators: New as in add new header image via the Customizer */ ?>
1007                                 <button type="button" class="button new"><?php _ex( 'Add new image', 'header image' ); ?></button>
1008                                 <div style="clear:both"></div>
1009                         </div>
1010                         <div class="choices">
1011                                 <span class="customize-control-title header-previously-uploaded">
1012                                         <?php _ex( 'Previously uploaded', 'custom headers' ); ?>
1013                                 </span>
1014                                 <div class="uploaded">
1015                                         <div class="list">
1016                                         </div>
1017                                 </div>
1018                                 <span class="customize-control-title header-default">
1019                                         <?php _ex( 'Suggested', 'custom headers' ); ?>
1020                                 </span>
1021                                 <div class="default">
1022                                         <div class="list">
1023                                         </div>
1024                                 </div>
1025                         </div>
1026                 </div>
1027                 <?php
1028         }
1029 }
1030
1031 /**
1032  * Widget Area Customize Control Class
1033  *
1034  */
1035 class WP_Widget_Area_Customize_Control extends WP_Customize_Control {
1036         public $type = 'sidebar_widgets';
1037         public $sidebar_id;
1038
1039         public function to_json() {
1040                 parent::to_json();
1041                 $exported_properties = array( 'sidebar_id' );
1042                 foreach ( $exported_properties as $key ) {
1043                         $this->json[ $key ] = $this->$key;
1044                 }
1045         }
1046
1047         public function render_content() {
1048                 ?>
1049                 <span class="button-secondary add-new-widget" tabindex="0">
1050                         <?php _e( 'Add a Widget' ); ?>
1051                 </span>
1052
1053                 <span class="reorder-toggle" tabindex="0">
1054                         <span class="reorder"><?php _ex( 'Reorder', 'Reorder widgets in Customizer' ); ?></span>
1055                         <span class="reorder-done"><?php _ex( 'Done', 'Cancel reordering widgets in Customizer'  ); ?></span>
1056                 </span>
1057                 <?php
1058         }
1059
1060         /**
1061          * Whether the current sidebar is rendered on the page.
1062          *
1063          * @since 4.0.0
1064          * @access public
1065          *
1066          * @return bool Whether sidebar is rendered.
1067          */
1068         public function active_callback() {
1069                 return $this->manager->widgets->is_sidebar_rendered( $this->sidebar_id );
1070         }
1071 }
1072
1073 /**
1074  * Widget Form Customize Control Class
1075  */
1076 class WP_Widget_Form_Customize_Control extends WP_Customize_Control {
1077         public $type = 'widget_form';
1078         public $widget_id;
1079         public $widget_id_base;
1080         public $sidebar_id;
1081         public $is_new = false;
1082         public $width;
1083         public $height;
1084         public $is_wide = false;
1085
1086         public function to_json() {
1087                 parent::to_json();
1088                 $exported_properties = array( 'widget_id', 'widget_id_base', 'sidebar_id', 'width', 'height', 'is_wide' );
1089                 foreach ( $exported_properties as $key ) {
1090                         $this->json[ $key ] = $this->$key;
1091                 }
1092         }
1093
1094         public function render_content() {
1095                 global $wp_registered_widgets;
1096                 require_once ABSPATH . '/wp-admin/includes/widgets.php';
1097
1098                 $widget = $wp_registered_widgets[ $this->widget_id ];
1099                 if ( ! isset( $widget['params'][0] ) ) {
1100                         $widget['params'][0] = array();
1101                 }
1102
1103                 $args = array(
1104                         'widget_id' => $widget['id'],
1105                         'widget_name' => $widget['name'],
1106                 );
1107
1108                 $args = wp_list_widget_controls_dynamic_sidebar( array( 0 => $args, 1 => $widget['params'][0] ) );
1109                 echo $this->manager->widgets->get_widget_control( $args );
1110         }
1111
1112         /**
1113          * Whether the current widget is rendered on the page.
1114          *
1115          * @since 4.0.0
1116          * @access public
1117          *
1118          * @return bool Whether the widget is rendered.
1119          */
1120         function active_callback() {
1121                 return $this->manager->widgets->is_widget_rendered( $this->widget_id );
1122         }
1123 }
1124