WordPress 4.2
[autoinstalls/wordpress.git] / wp-includes / class-wp-customize-control.php
1 <?php
2 /**
3  * WordPress Customize Control classes
4  *
5  * @package WordPress
6  * @subpackage Customize
7  * @since 3.4.0
8  */
9
10 /**
11  * Customize Control class.
12  *
13  * @since 3.4.0
14  */
15 class WP_Customize_Control {
16
17         /**
18          * Incremented with each new class instantiation, then stored in $instance_number.
19          *
20          * Used when sorting two instances whose priorities are equal.
21          *
22          * @since 4.1.0
23          * @access protected
24          * @var int
25          */
26         protected static $instance_count = 0;
27
28         /**
29          * Order in which this instance was created in relation to other instances.
30          *
31          * @since 4.1.0
32          * @access public
33          * @var int
34          */
35         public $instance_number;
36
37         /**
38          * @access public
39          * @var WP_Customize_Manager
40          */
41         public $manager;
42
43         /**
44          * @access public
45          * @var string
46          */
47         public $id;
48
49         /**
50          * All settings tied to the control.
51          *
52          * @access public
53          * @var array
54          */
55         public $settings;
56
57         /**
58          * The primary setting for the control (if there is one).
59          *
60          * @access public
61          * @var string
62          */
63         public $setting = 'default';
64
65         /**
66          * @access public
67          * @var int
68          */
69         public $priority = 10;
70
71         /**
72          * @access public
73          * @var string
74          */
75         public $section = '';
76
77         /**
78          * @access public
79          * @var string
80          */
81         public $label = '';
82
83         /**
84          * @access public
85          * @var string
86          */
87         public $description = '';
88
89         /**
90          * @todo: Remove choices
91          *
92          * @access public
93          * @var array
94          */
95         public $choices = array();
96
97         /**
98          * @access public
99          * @var array
100          */
101         public $input_attrs = array();
102
103         /**
104          * @deprecated It is better to just call the json() method
105          * @access public
106          * @var array
107          */
108         public $json = array();
109
110         /**
111          * @access public
112          * @var string
113          */
114         public $type = 'text';
115
116         /**
117          * Callback.
118          *
119          * @since 4.0.0
120          * @access public
121          *
122          * @see WP_Customize_Control::active()
123          *
124          * @var callable Callback is called with one argument, the instance of
125          *               WP_Customize_Control, and returns bool to indicate whether
126          *               the control is active (such as it relates to the URL
127          *               currently being previewed).
128          */
129         public $active_callback = '';
130
131         /**
132          * Constructor.
133          *
134          * Supplied $args override class property defaults.
135          *
136          * If $args['settings'] is not defined, use the $id as the setting ID.
137          *
138          * @since 3.4.0
139          *
140          * @param WP_Customize_Manager $manager
141          * @param string $id
142          * @param array $args
143          */
144         public function __construct( $manager, $id, $args = array() ) {
145                 $keys = array_keys( get_object_vars( $this ) );
146                 foreach ( $keys as $key ) {
147                         if ( isset( $args[ $key ] ) ) {
148                                 $this->$key = $args[ $key ];
149                         }
150                 }
151
152                 $this->manager = $manager;
153                 $this->id = $id;
154                 if ( empty( $this->active_callback ) ) {
155                         $this->active_callback = array( $this, 'active_callback' );
156                 }
157                 self::$instance_count += 1;
158                 $this->instance_number = self::$instance_count;
159
160                 // Process settings.
161                 if ( empty( $this->settings ) ) {
162                         $this->settings = $id;
163                 }
164
165                 $settings = array();
166                 if ( is_array( $this->settings ) ) {
167                         foreach ( $this->settings as $key => $setting ) {
168                                 $settings[ $key ] = $this->manager->get_setting( $setting );
169                         }
170                 } else {
171                         $this->setting = $this->manager->get_setting( $this->settings );
172                         $settings['default'] = $this->setting;
173                 }
174                 $this->settings = $settings;
175         }
176
177         /**
178          * Enqueue control related scripts/styles.
179          *
180          * @since 3.4.0
181          */
182         public function enqueue() {}
183
184         /**
185          * Check whether control is active to current Customizer preview.
186          *
187          * @since 4.0.0
188          * @access public
189          *
190          * @return bool Whether the control is active to the current preview.
191          */
192         final public function active() {
193                 $control = $this;
194                 $active = call_user_func( $this->active_callback, $this );
195
196                 /**
197                  * Filter response of WP_Customize_Control::active().
198                  *
199                  * @since 4.0.0
200                  *
201                  * @param bool                 $active  Whether the Customizer control is active.
202                  * @param WP_Customize_Control $control WP_Customize_Control instance.
203                  */
204                 $active = apply_filters( 'customize_control_active', $active, $control );
205
206                 return $active;
207         }
208
209         /**
210          * Default callback used when invoking WP_Customize_Control::active().
211          *
212          * Subclasses can override this with their specific logic, or they may
213          * provide an 'active_callback' argument to the constructor.
214          *
215          * @since 4.0.0
216          * @access public
217          *
218          * @return bool Always true.
219          */
220         public function active_callback() {
221                 return true;
222         }
223
224         /**
225          * Fetch a setting's value.
226          * Grabs the main setting by default.
227          *
228          * @since 3.4.0
229          *
230          * @param string $setting_key
231          * @return mixed The requested setting's value, if the setting exists.
232          */
233         final public function value( $setting_key = 'default' ) {
234                 if ( isset( $this->settings[ $setting_key ] ) ) {
235                         return $this->settings[ $setting_key ]->value();
236                 }
237         }
238
239         /**
240          * Refresh the parameters passed to the JavaScript via JSON.
241          *
242          * @since 3.4.0
243          */
244         public function to_json() {
245                 $this->json['settings'] = array();
246                 foreach ( $this->settings as $key => $setting ) {
247                         $this->json['settings'][ $key ] = $setting->id;
248                 }
249
250                 $this->json['type'] = $this->type;
251                 $this->json['priority'] = $this->priority;
252                 $this->json['active'] = $this->active();
253                 $this->json['section'] = $this->section;
254                 $this->json['content'] = $this->get_content();
255                 $this->json['label'] = $this->label;
256                 $this->json['description'] = $this->description;
257                 $this->json['instanceNumber'] = $this->instance_number;
258         }
259
260         /**
261          * Get the data to export to the client via JSON.
262          *
263          * @since 4.1.0
264          *
265          * @return array Array of parameters passed to the JavaScript.
266          */
267         public function json() {
268                 $this->to_json();
269                 return $this->json;
270         }
271
272         /**
273          * Check if the theme supports the control and check user capabilities.
274          *
275          * @since 3.4.0
276          *
277          * @return bool False if theme doesn't support the control or user doesn't have the required permissions, otherwise true.
278          */
279         final public function check_capabilities() {
280                 foreach ( $this->settings as $setting ) {
281                         if ( ! $setting->check_capabilities() )
282                                 return false;
283                 }
284
285                 $section = $this->manager->get_section( $this->section );
286                 if ( isset( $section ) && ! $section->check_capabilities() )
287                         return false;
288
289                 return true;
290         }
291
292         /**
293          * Get the control's content for insertion into the Customizer pane.
294          *
295          * @since 4.1.0
296          *
297          * @return string Contents of the control.
298          */
299         final public function get_content() {
300                 ob_start();
301                 $this->maybe_render();
302                 $template = trim( ob_get_contents() );
303                 ob_end_clean();
304                 return $template;
305         }
306
307         /**
308          * Check capabilities and render the control.
309          *
310          * @since 3.4.0
311          * @uses WP_Customize_Control::render()
312          */
313         final public function maybe_render() {
314                 if ( ! $this->check_capabilities() )
315                         return;
316
317                 /**
318                  * Fires just before the current Customizer control is rendered.
319                  *
320                  * @since 3.4.0
321                  *
322                  * @param WP_Customize_Control $this WP_Customize_Control instance.
323                  */
324                 do_action( 'customize_render_control', $this );
325
326                 /**
327                  * Fires just before a specific Customizer control is rendered.
328                  *
329                  * The dynamic portion of the hook name, `$this->id`, refers to
330                  * the control ID.
331                  *
332                  * @since 3.4.0
333                  *
334                  * @param WP_Customize_Control $this {@see WP_Customize_Control} instance.
335                  */
336                 do_action( 'customize_render_control_' . $this->id, $this );
337
338                 $this->render();
339         }
340
341         /**
342          * Renders the control wrapper and calls $this->render_content() for the internals.
343          *
344          * @since 3.4.0
345          */
346         protected function render() {
347                 $id    = 'customize-control-' . str_replace( '[', '-', str_replace( ']', '', $this->id ) );
348                 $class = 'customize-control customize-control-' . $this->type;
349
350                 ?><li id="<?php echo esc_attr( $id ); ?>" class="<?php echo esc_attr( $class ); ?>">
351                         <?php $this->render_content(); ?>
352                 </li><?php
353         }
354
355         /**
356          * Get the data link attribute for a setting.
357          *
358          * @since 3.4.0
359          *
360          * @param string $setting_key
361          * @return string Data link parameter, if $setting_key is a valid setting, empty string otherwise.
362          */
363         public function get_link( $setting_key = 'default' ) {
364                 if ( ! isset( $this->settings[ $setting_key ] ) )
365                         return '';
366
367                 return 'data-customize-setting-link="' . esc_attr( $this->settings[ $setting_key ]->id ) . '"';
368         }
369
370         /**
371          * Render the data link attribute for the control's input element.
372          *
373          * @since 3.4.0
374          * @uses WP_Customize_Control::get_link()
375          *
376          * @param string $setting_key
377          */
378         public function link( $setting_key = 'default' ) {
379                 echo $this->get_link( $setting_key );
380         }
381
382         /**
383          * Render the custom attributes for the control's input element.
384          *
385          * @since 4.0.0
386          * @access public
387          */
388         public function input_attrs() {
389                 foreach( $this->input_attrs as $attr => $value ) {
390                         echo $attr . '="' . esc_attr( $value ) . '" ';
391                 }
392         }
393
394         /**
395          * Render the control's content.
396          *
397          * Allows the content to be overriden without having to rewrite the wrapper in $this->render().
398          *
399          * Supports basic input types `text`, `checkbox`, `textarea`, `radio`, `select` and `dropdown-pages`.
400          * Additional input types such as `email`, `url`, `number`, `hidden` and `date` are supported implicitly.
401          *
402          * Control content can alternately be rendered in JS. See {@see WP_Customize_Control::print_template()}.
403          *
404          * @since 3.4.0
405          */
406         protected function render_content() {
407                 switch( $this->type ) {
408                         case 'checkbox':
409                                 ?>
410                                 <label>
411                                         <input type="checkbox" value="<?php echo esc_attr( $this->value() ); ?>" <?php $this->link(); checked( $this->value() ); ?> />
412                                         <?php echo esc_html( $this->label ); ?>
413                                         <?php if ( ! empty( $this->description ) ) : ?>
414                                                 <span class="description customize-control-description"><?php echo $this->description; ?></span>
415                                         <?php endif; ?>
416                                 </label>
417                                 <?php
418                                 break;
419                         case 'radio':
420                                 if ( empty( $this->choices ) )
421                                         return;
422
423                                 $name = '_customize-radio-' . $this->id;
424
425                                 if ( ! empty( $this->label ) ) : ?>
426                                         <span class="customize-control-title"><?php echo esc_html( $this->label ); ?></span>
427                                 <?php endif;
428                                 if ( ! empty( $this->description ) ) : ?>
429                                         <span class="description customize-control-description"><?php echo $this->description ; ?></span>
430                                 <?php endif;
431
432                                 foreach ( $this->choices as $value => $label ) :
433                                         ?>
434                                         <label>
435                                                 <input type="radio" value="<?php echo esc_attr( $value ); ?>" name="<?php echo esc_attr( $name ); ?>" <?php $this->link(); checked( $this->value(), $value ); ?> />
436                                                 <?php echo esc_html( $label ); ?><br/>
437                                         </label>
438                                         <?php
439                                 endforeach;
440                                 break;
441                         case 'select':
442                                 if ( empty( $this->choices ) )
443                                         return;
444
445                                 ?>
446                                 <label>
447                                         <?php if ( ! empty( $this->label ) ) : ?>
448                                                 <span class="customize-control-title"><?php echo esc_html( $this->label ); ?></span>
449                                         <?php endif;
450                                         if ( ! empty( $this->description ) ) : ?>
451                                                 <span class="description customize-control-description"><?php echo $this->description; ?></span>
452                                         <?php endif; ?>
453
454                                         <select <?php $this->link(); ?>>
455                                                 <?php
456                                                 foreach ( $this->choices as $value => $label )
457                                                         echo '<option value="' . esc_attr( $value ) . '"' . selected( $this->value(), $value, false ) . '>' . $label . '</option>';
458                                                 ?>
459                                         </select>
460                                 </label>
461                                 <?php
462                                 break;
463                         case 'textarea':
464                                 ?>
465                                 <label>
466                                         <?php if ( ! empty( $this->label ) ) : ?>
467                                                 <span class="customize-control-title"><?php echo esc_html( $this->label ); ?></span>
468                                         <?php endif;
469                                         if ( ! empty( $this->description ) ) : ?>
470                                                 <span class="description customize-control-description"><?php echo $this->description; ?></span>
471                                         <?php endif; ?>
472                                         <textarea rows="5" <?php $this->link(); ?>><?php echo esc_textarea( $this->value() ); ?></textarea>
473                                 </label>
474                                 <?php
475                                 break;
476                         case 'dropdown-pages':
477                                 $dropdown = wp_dropdown_pages(
478                                         array(
479                                                 'name'              => '_customize-dropdown-pages-' . $this->id,
480                                                 'echo'              => 0,
481                                                 'show_option_none'  => __( '&mdash; Select &mdash;' ),
482                                                 'option_none_value' => '0',
483                                                 'selected'          => $this->value(),
484                                         )
485                                 );
486
487                                 // Hackily add in the data link parameter.
488                                 $dropdown = str_replace( '<select', '<select ' . $this->get_link(), $dropdown );
489
490                                 printf(
491                                         '<label class="customize-control-select"><span class="customize-control-title">%s</span> %s</label>',
492                                         $this->label,
493                                         $dropdown
494                                 );
495                                 break;
496                         default:
497                                 ?>
498                                 <label>
499                                         <?php if ( ! empty( $this->label ) ) : ?>
500                                                 <span class="customize-control-title"><?php echo esc_html( $this->label ); ?></span>
501                                         <?php endif;
502                                         if ( ! empty( $this->description ) ) : ?>
503                                                 <span class="description customize-control-description"><?php echo $this->description; ?></span>
504                                         <?php endif; ?>
505                                         <input type="<?php echo esc_attr( $this->type ); ?>" <?php $this->input_attrs(); ?> value="<?php echo esc_attr( $this->value() ); ?>" <?php $this->link(); ?> />
506                                 </label>
507                                 <?php
508                                 break;
509                 }
510         }
511
512         /**
513          * Render the control's JS template.
514          *
515          * This function is only run for control types that have been registered with
516          * {@see WP_Customize_Manager::register_control_type()}.
517          *
518          * In the future, this will also print the template for the control's container
519          * element and be override-able.
520          *
521          * @since 4.1.0
522          */
523         final public function print_template() {
524                 ?>
525                 <script type="text/html" id="tmpl-customize-control-<?php echo $this->type; ?>-content">
526                         <?php $this->content_template(); ?>
527                 </script>
528                 <?php
529         }
530
531         /**
532          * An Underscore (JS) template for this control's content (but not its container).
533          *
534          * Class variables for this control class are available in the `data` JS object;
535          * export custom variables by overriding {@see WP_Customize_Control::to_json()}.
536          *
537          * @see WP_Customize_Control::print_template()
538          *
539          * @since 4.1.0
540          */
541         protected function content_template() {}
542
543 }
544
545 /**
546  * Customize Color Control class.
547  *
548  * @since 3.4.0
549  *
550  * @see WP_Customize_Control
551  */
552 class WP_Customize_Color_Control extends WP_Customize_Control {
553         /**
554          * @access public
555          * @var string
556          */
557         public $type = 'color';
558
559         /**
560          * @access public
561          * @var array
562          */
563         public $statuses;
564
565         /**
566          * Constructor.
567          *
568          * @since 3.4.0
569          * @uses WP_Customize_Control::__construct()
570          *
571          * @param WP_Customize_Manager $manager
572          * @param string $id
573          * @param array $args
574          */
575         public function __construct( $manager, $id, $args = array() ) {
576                 $this->statuses = array( '' => __('Default') );
577                 parent::__construct( $manager, $id, $args );
578         }
579
580         /**
581          * Enqueue scripts/styles for the color picker.
582          *
583          * @since 3.4.0
584          */
585         public function enqueue() {
586                 wp_enqueue_script( 'wp-color-picker' );
587                 wp_enqueue_style( 'wp-color-picker' );
588         }
589
590         /**
591          * Refresh the parameters passed to the JavaScript via JSON.
592          *
593          * @since 3.4.0
594          * @uses WP_Customize_Control::to_json()
595          */
596         public function to_json() {
597                 parent::to_json();
598                 $this->json['statuses'] = $this->statuses;
599                 $this->json['defaultValue'] = $this->setting->default;
600         }
601
602         /**
603          * Don't render the control content from PHP, as it's rendered via JS on load.
604          *
605          * @since 3.4.0
606          */
607         public function render_content() {}
608
609         /**
610          * Render a JS template for the content of the color picker control.
611          *
612          * @since 4.1.0
613          */
614         public function content_template() {
615                 ?>
616                 <# var defaultValue = '';
617                 if ( data.defaultValue ) {
618                         if ( '#' !== data.defaultValue.substring( 0, 1 ) ) {
619                                 defaultValue = '#' + data.defaultValue;
620                         } else {
621                                 defaultValue = data.defaultValue;
622                         }
623                         defaultValue = ' data-default-color=' + defaultValue; // Quotes added automatically.
624                 } #>
625                 <label>
626                         <# if ( data.label ) { #>
627                                 <span class="customize-control-title">{{{ data.label }}}</span>
628                         <# } #>
629                         <# if ( data.description ) { #>
630                                 <span class="description customize-control-description">{{{ data.description }}}</span>
631                         <# } #>
632                         <div class="customize-control-content">
633                                 <input class="color-picker-hex" type="text" maxlength="7" placeholder="<?php esc_attr_e( 'Hex Value' ); ?>" {{ defaultValue }} />
634                         </div>
635                 </label>
636                 <?php
637         }
638 }
639
640 /**
641  * Customize Media Control class.
642  *
643  * @since 4.2.0
644  *
645  * @see WP_Customize_Control
646  */
647 class WP_Customize_Media_Control extends WP_Customize_Control {
648         /**
649          * Control type.
650          *
651          * @since 4.2.0
652          * @access public
653          * @var string
654          */
655         public $type = 'media';
656
657         /**
658          * Media control mime type.
659          *
660          * @since 4.2.0
661          * @access public
662          * @var string
663          */
664         public $mime_type = '';
665
666         /**
667          * Button labels.
668          *
669          * @since 4.2.0
670          * @access public
671          * @var array
672          */
673         public $button_labels = array();
674
675         /**
676          * Constructor.
677          *
678          * @since 4.1.0
679          * @since 4.2.0 Moved from WP_Customize_Upload_Control.
680          *
681          * @param WP_Customize_Manager $manager {@see WP_Customize_Manager} instance.
682          */
683         public function __construct( $manager, $id, $args = array() ) {
684                 parent::__construct( $manager, $id, $args );
685
686                 $this->button_labels = array(
687                         'select'       => __( 'Select File' ),
688                         'change'       => __( 'Change File' ),
689                         'default'      => __( 'Default' ),
690                         'remove'       => __( 'Remove' ),
691                         'placeholder'  => __( 'No file selected' ),
692                         'frame_title'  => __( 'Select File' ),
693                         'frame_button' => __( 'Choose File' ),
694                 );
695         }
696
697         /**
698          * Enqueue control related scripts/styles.
699          *
700          * @since 3.4.0
701          * @since 4.2.0 Moved from WP_Customize_Upload_Control.
702          */
703         public function enqueue() {
704                 wp_enqueue_media();
705         }
706
707         /**
708          * Refresh the parameters passed to the JavaScript via JSON.
709          *
710          * @since 3.4.0
711          * @since 4.2.0 Moved from WP_Customize_Upload_Control.
712          *
713          * @see WP_Customize_Control::to_json()
714          */
715         public function to_json() {
716                 parent::to_json();
717                 $this->json['mime_type'] = $this->mime_type;
718                 $this->json['button_labels'] = $this->button_labels;
719
720                 $value = $this->value();
721
722                 if ( is_object( $this->setting ) ) {
723                         if ( $this->setting->default ) {
724                                 // Fake an attachment model - needs all fields used by template.
725                                 // Note that the default value must be a URL, NOT an attachment ID.
726                                 $type = in_array( substr( $this->setting->default, -3 ), array( 'jpg', 'png', 'gif', 'bmp' ) ) ? 'image' : 'document';
727                                 $default_attachment = array(
728                                         'id' => 1,
729                                         'url' => $this->setting->default,
730                                         'type' => $type,
731                                         'icon' => wp_mime_type_icon( $type ),
732                                         'title' => basename( $this->setting->default ),
733                                 );
734
735                                 if ( 'image' === $type ) {
736                                         $default_attachment['sizes'] = array(
737                                                 'full' => array( 'url' => $this->setting->default ),
738                                         );
739                                 }
740
741                                 $this->json['defaultAttachment'] = $default_attachment;
742                         }
743
744                         if ( $value && $this->setting->default && $value === $this->setting->default ) {
745                                 // Set the default as the attachment.
746                                 $this->json['attachment'] = $this->json['defaultAttachment'];
747                         } elseif ( $value ) {
748                                 $this->json['attachment'] = wp_prepare_attachment_for_js( $value );
749                         }
750                 }
751         }
752
753         /**
754          * Don't render any content for this control from PHP.
755          *
756          * @since 3.4.0
757          * @since 4.2.0 Moved from WP_Customize_Upload_Control.
758          *
759          * @see WP_Customize_Media_Control::content_template()
760          */
761         public function render_content() {}
762
763         /**
764          * Render a JS template for the content of the media control.
765          *
766          * @since 4.1.0
767          * @since 4.2.0 Moved from WP_Customize_Upload_Control.
768          */
769         public function content_template() {
770                 ?>
771                 <label for="{{ data.settings['default'] }}-button">
772                         <# if ( data.label ) { #>
773                                 <span class="customize-control-title">{{ data.label }}</span>
774                         <# } #>
775                         <# if ( data.description ) { #>
776                                 <span class="description customize-control-description">{{{ data.description }}}</span>
777                         <# } #>
778                 </label>
779
780                 <# if ( data.attachment && data.attachment.id ) { #>
781                         <div class="current">
782                                 <div class="container">
783                                         <div class="attachment-media-view attachment-media-view-{{ data.attachment.type }} {{ data.attachment.orientation }}">
784                                                 <div class="thumbnail thumbnail-{{ data.attachment.type }}">
785                                                         <# if ( 'image' === data.attachment.type && data.attachment.sizes && data.attachment.sizes.medium ) { #>
786                                                                 <img class="attachment-thumb" src="{{ data.attachment.sizes.medium.url }}" draggable="false" />
787                                                         <# } else if ( 'image' === data.attachment.type && data.attachment.sizes && data.attachment.sizes.full ) { #>
788                                                                 <img class="attachment-thumb" src="{{ data.attachment.sizes.full.url }}" draggable="false" />
789                                                         <# } else if ( 'audio' === data.attachment.type ) { #>
790                                                                 <# if ( data.attachment.image && data.attachment.image.src && data.attachment.image.src !== data.attachment.icon ) { #>
791                                                                         <img src="{{ data.attachment.image.src }}" class="thumbnail" draggable="false" />
792                                                                 <# } else { #>
793                                                                         <img src="{{ data.attachment.icon }}" class="attachment-thumb type-icon" draggable="false" />
794                                                                 <# } #>
795                                                                 <p class="attachment-meta attachment-meta-title">&#8220;{{ data.attachment.title }}&#8221;</p>
796                                                                 <# if ( data.attachment.album || data.attachment.meta.album ) { #>
797                                                                 <p class="attachment-meta"><em>{{ data.attachment.album || data.attachment.meta.album }}</em></p>
798                                                                 <# } #>
799                                                                 <# if ( data.attachment.artist || data.attachment.meta.artist ) { #>
800                                                                 <p class="attachment-meta">{{ data.attachment.artist || data.attachment.meta.artist }}</p>
801                                                                 <# } #>
802                                                                 <audio style="visibility: hidden" controls class="wp-audio-shortcode" width="100%" preload="none">
803                                                                         <source type="{{ data.attachment.mime }}" src="{{ data.attachment.url }}"/>
804                                                                 </audio>
805                                                         <# } else if ( 'video' === data.attachment.type ) { #>
806                                                                 <div class="wp-media-wrapper wp-video">
807                                                                         <video controls="controls" class="wp-video-shortcode" preload="metadata"
808                                                                                 <# if ( data.attachment.image && data.attachment.image.src !== data.attachment.icon ) { #>poster="{{ data.attachment.image.src }}"<# } #>>
809                                                                                 <source type="{{ data.attachment.mime }}" src="{{ data.attachment.url }}"/>
810                                                                         </video>
811                                                                 </div>
812                                                         <# } else { #>
813                                                                 <img class="attachment-thumb type-icon" src="{{ data.attachment.icon }}" class="icon" draggable="false" />
814                                                                 <p class="attachment-title">{{ data.attachment.title }}</p>
815                                                         <# } #>
816                                                 </div>
817                                         </div>
818                                 </div>
819                         </div>
820                         <div class="actions">
821                                 <button type="button" class="button remove-button"><?php echo $this->button_labels['remove']; ?></button>
822                                 <button type="button" class="button upload-button" id="{{ data.settings['default'] }}-button"><?php echo $this->button_labels['change']; ?></button>
823                                 <div style="clear:both"></div>
824                         </div>
825                 <# } else { #>
826                         <div class="current">
827                                 <div class="container">
828                                         <div class="placeholder">
829                                                 <div class="inner">
830                                                         <span>
831                                                                 <?php echo $this->button_labels['placeholder']; ?>
832                                                         </span>
833                                                 </div>
834                                         </div>
835                                 </div>
836                         </div>
837                         <div class="actions">
838                                 <# if ( data.defaultAttachment ) { #>
839                                         <button type="button" class="button default-button"><?php echo $this->button_labels['default']; ?></button>
840                                 <# } #>
841                                 <button type="button" class="button upload-button" id="{{ data.settings['default'] }}-button"><?php echo $this->button_labels['select']; ?></button>
842                                 <div style="clear:both"></div>
843                         </div>
844                 <# } #>
845                 <?php
846         }
847 }
848
849 /**
850  * Customize Upload Control Class.
851  *
852  * @since 3.4.0
853  *
854  * @see WP_Customize_Media_Control
855  */
856 class WP_Customize_Upload_Control extends WP_Customize_Media_Control {
857         public $type          = 'upload';
858         public $mime_type     = '';
859         public $button_labels = array();
860         public $removed = ''; // unused
861         public $context; // unused
862         public $extensions = array(); // unused
863
864         /**
865          * Refresh the parameters passed to the JavaScript via JSON.
866          *
867          * @since 3.4.0
868          *
869          * @uses WP_Customize_Media_Control::to_json()
870          */
871         public function to_json() {
872                 parent::to_json();
873
874                 $value = $this->value();
875                 if ( $value ) {
876                         // Get the attachment model for the existing file.
877                         $attachment_id = attachment_url_to_postid( $value );
878                         if ( $attachment_id ) {
879                                 $this->json['attachment'] = wp_prepare_attachment_for_js( $attachment_id );
880                         }
881                 }
882         }
883 }
884
885 /**
886  * Customize Image Control class.
887  *
888  * @since 3.4.0
889  *
890  * @see WP_Customize_Upload_Control
891  */
892 class WP_Customize_Image_Control extends WP_Customize_Upload_Control {
893         public $type = 'image';
894         public $mime_type = 'image';
895
896         /**
897          * Constructor.
898          *
899          * @since 3.4.0
900          * @uses WP_Customize_Upload_Control::__construct()
901          *
902          * @param WP_Customize_Manager $manager
903          * @param string $id
904          * @param array  $args
905          */
906         public function __construct( $manager, $id, $args = array() ) {
907                 parent::__construct( $manager, $id, $args );
908
909                 $this->button_labels = array(
910                         'select'       => __( 'Select Image' ),
911                         'change'       => __( 'Change Image' ),
912                         'remove'       => __( 'Remove' ),
913                         'default'      => __( 'Default' ),
914                         'placeholder'  => __( 'No image selected' ),
915                         'frame_title'  => __( 'Select Image' ),
916                         'frame_button' => __( 'Choose Image' ),
917                 );
918         }
919
920         /**
921          * @since 3.4.2
922          * @deprecated 4.1.0
923          */
924         public function prepare_control() {}
925
926         /**
927          * @since 3.4.0
928          * @deprecated 4.1.0
929          *
930          * @param string $id
931          * @param string $label
932          * @param mixed $callback
933          */
934         public function add_tab( $id, $label, $callback ) {}
935
936         /**
937          * @since 3.4.0
938          * @deprecated 4.1.0
939          *
940          * @param string $id
941          */
942         public function remove_tab( $id ) {}
943
944         /**
945          * @since 3.4.0
946          * @deprecated 4.1.0
947          *
948          * @param string $url
949          * @param string $thumbnail_url
950          */
951         public function print_tab_image( $url, $thumbnail_url = null ) {}
952 }
953
954 /**
955  * Customize Background Image Control class.
956  *
957  * @since 3.4.0
958  *
959  * @see WP_Customize_Image_Control
960  */
961 class WP_Customize_Background_Image_Control extends WP_Customize_Image_Control {
962         public $type = 'background';
963
964         /**
965          * Constructor.
966          *
967          * @since 3.4.0
968          * @uses WP_Customize_Image_Control::__construct()
969          *
970          * @param WP_Customize_Manager $manager
971          */
972         public function __construct( $manager ) {
973                 parent::__construct( $manager, 'background_image', array(
974                         'label'    => __( 'Background Image' ),
975                         'section'  => 'background_image',
976                 ) );
977         }
978
979         /**
980          * Enqueue control related scripts/styles.
981          *
982          * @since 4.1.0
983          */
984         public function enqueue() {
985                 parent::enqueue();
986
987                 wp_localize_script( 'customize-controls', '_wpCustomizeBackground', array(
988                         'nonces' => array(
989                                 'add' => wp_create_nonce( 'background-add' ),
990                         ),
991                 ) );
992         }
993 }
994
995 /**
996  * Customize Header Image Control class.
997  *
998  * @since 3.4.0
999  *
1000  * @see WP_Customize_Image_Control
1001  */
1002 class WP_Customize_Header_Image_Control extends WP_Customize_Image_Control {
1003         public $type = 'header';
1004         public $uploaded_headers;
1005         public $default_headers;
1006
1007         /**
1008          * @param WP_Customize_Manager $manager
1009          */
1010         public function __construct( $manager ) {
1011                 parent::__construct( $manager, 'header_image', array(
1012                         'label'    => __( 'Header Image' ),
1013                         'settings' => array(
1014                                 'default' => 'header_image',
1015                                 'data'    => 'header_image_data',
1016                         ),
1017                         'section'  => 'header_image',
1018                         'removed'  => 'remove-header',
1019                         'get_url'  => 'get_header_image',
1020                 ) );
1021
1022         }
1023
1024         public function enqueue() {
1025                 wp_enqueue_media();
1026                 wp_enqueue_script( 'customize-views' );
1027
1028                 $this->prepare_control();
1029
1030                 wp_localize_script( 'customize-views', '_wpCustomizeHeader', array(
1031                         'data' => array(
1032                                 'width' => absint( get_theme_support( 'custom-header', 'width' ) ),
1033                                 'height' => absint( get_theme_support( 'custom-header', 'height' ) ),
1034                                 'flex-width' => absint( get_theme_support( 'custom-header', 'flex-width' ) ),
1035                                 'flex-height' => absint( get_theme_support( 'custom-header', 'flex-height' ) ),
1036                                 'currentImgSrc' => $this->get_current_image_src(),
1037                         ),
1038                         'nonces' => array(
1039                                 'add' => wp_create_nonce( 'header-add' ),
1040                                 'remove' => wp_create_nonce( 'header-remove' ),
1041                         ),
1042                         'uploads' => $this->uploaded_headers,
1043                         'defaults' => $this->default_headers
1044                 ) );
1045
1046                 parent::enqueue();
1047         }
1048
1049         public function prepare_control() {
1050                 global $custom_image_header;
1051                 if ( empty( $custom_image_header ) ) {
1052                         return;
1053                 }
1054
1055                 // Process default headers and uploaded headers.
1056                 $custom_image_header->process_default_headers();
1057                 $this->default_headers = $custom_image_header->get_default_header_images();
1058                 $this->uploaded_headers = $custom_image_header->get_uploaded_header_images();
1059         }
1060
1061         public function print_header_image_template() {
1062                 ?>
1063                 <script type="text/template" id="tmpl-header-choice">
1064                         <# if (data.random) { #>
1065                                         <button type="button" class="button display-options random">
1066                                                 <span class="dashicons dashicons-randomize dice"></span>
1067                                                 <# if ( data.type === 'uploaded' ) { #>
1068                                                         <?php _e( 'Randomize uploaded headers' ); ?>
1069                                                 <# } else if ( data.type === 'default' ) { #>
1070                                                         <?php _e( 'Randomize suggested headers' ); ?>
1071                                                 <# } #>
1072                                         </button>
1073
1074                         <# } else { #>
1075
1076                         <# if (data.type === 'uploaded') { #>
1077                                 <div class="dashicons dashicons-no close"></div>
1078                         <# } #>
1079
1080                         <button type="button" class="choice thumbnail"
1081                                 data-customize-image-value="{{{data.header.url}}}"
1082                                 data-customize-header-image-data="{{JSON.stringify(data.header)}}">
1083                                 <span class="screen-reader-text"><?php _e( 'Set image' ); ?></span>
1084                                 <img src="{{{data.header.thumbnail_url}}}" alt="{{{data.header.alt_text || data.header.description}}}">
1085                         </button>
1086
1087                         <# } #>
1088                 </script>
1089
1090                 <script type="text/template" id="tmpl-header-current">
1091                         <# if (data.choice) { #>
1092                                 <# if (data.random) { #>
1093
1094                         <div class="placeholder">
1095                                 <div class="inner">
1096                                         <span><span class="dashicons dashicons-randomize dice"></span>
1097                                         <# if ( data.type === 'uploaded' ) { #>
1098                                                 <?php _e( 'Randomizing uploaded headers' ); ?>
1099                                         <# } else if ( data.type === 'default' ) { #>
1100                                                 <?php _e( 'Randomizing suggested headers' ); ?>
1101                                         <# } #>
1102                                         </span>
1103                                 </div>
1104                         </div>
1105
1106                                 <# } else { #>
1107
1108                         <img src="{{{data.header.thumbnail_url}}}" alt="{{{data.header.alt_text || data.header.description}}}" tabindex="0"/>
1109
1110                                 <# } #>
1111                         <# } else { #>
1112
1113                         <div class="placeholder">
1114                                 <div class="inner">
1115                                         <span>
1116                                                 <?php _e( 'No image set' ); ?>
1117                                         </span>
1118                                 </div>
1119                         </div>
1120
1121                         <# } #>
1122                 </script>
1123                 <?php
1124         }
1125
1126         public function get_current_image_src() {
1127                 $src = $this->value();
1128                 if ( isset( $this->get_url ) ) {
1129                         $src = call_user_func( $this->get_url, $src );
1130                         return $src;
1131                 }
1132                 return null;
1133         }
1134
1135         public function render_content() {
1136                 $this->print_header_image_template();
1137                 $visibility = $this->get_current_image_src() ? '' : ' style="display:none" ';
1138                 $width = absint( get_theme_support( 'custom-header', 'width' ) );
1139                 $height = absint( get_theme_support( 'custom-header', 'height' ) );
1140                 ?>
1141
1142
1143                 <div class="customize-control-content">
1144                         <p class="customizer-section-intro">
1145                                 <?php
1146                                 if ( $width && $height ) {
1147                                         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 );
1148                                 } elseif ( $width ) {
1149                                         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 );
1150                                 } else {
1151                                         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 );
1152                                 }
1153                                 ?>
1154                         </p>
1155                         <div class="current">
1156                                 <span class="customize-control-title">
1157                                         <?php _e( 'Current header' ); ?>
1158                                 </span>
1159                                 <div class="container">
1160                                 </div>
1161                         </div>
1162                         <div class="actions">
1163                                 <?php /* translators: Hide as in hide header image via the Customizer */ ?>
1164                                 <button type="button"<?php echo $visibility ?> class="button remove"><?php _ex( 'Hide image', 'custom header' ); ?></button>
1165                                 <?php /* translators: New as in add new header image via the Customizer */ ?>
1166                                 <button type="button" class="button new"><?php _ex( 'Add new image', 'header image' ); ?></button>
1167                                 <div style="clear:both"></div>
1168                         </div>
1169                         <div class="choices">
1170                                 <span class="customize-control-title header-previously-uploaded">
1171                                         <?php _ex( 'Previously uploaded', 'custom headers' ); ?>
1172                                 </span>
1173                                 <div class="uploaded">
1174                                         <div class="list">
1175                                         </div>
1176                                 </div>
1177                                 <span class="customize-control-title header-default">
1178                                         <?php _ex( 'Suggested', 'custom headers' ); ?>
1179                                 </span>
1180                                 <div class="default">
1181                                         <div class="list">
1182                                         </div>
1183                                 </div>
1184                         </div>
1185                 </div>
1186                 <?php
1187         }
1188 }
1189
1190 /**
1191  * Customize Theme Control class.
1192  *
1193  * @since 4.2.0
1194  *
1195  * @see WP_Customize_Control
1196  */
1197 class WP_Customize_Theme_Control extends WP_Customize_Control {
1198
1199         /**
1200          * Customize control type.
1201          *
1202          * @since 4.2.0
1203          * @access public
1204          * @var string
1205          */
1206         public $type = 'theme';
1207
1208         /**
1209          * Theme object.
1210          *
1211          * @since 4.2.0
1212          * @access public
1213          * @var WP_Theme
1214          */
1215         public $theme;
1216
1217         /**
1218          * Refresh the parameters passed to the JavaScript via JSON.
1219          *
1220          * @since 4.2.0
1221          * @access public
1222          *
1223          * @see WP_Customize_Control::to_json()
1224          */
1225         public function to_json() {
1226                 parent::to_json();
1227                 $this->json['theme'] = $this->theme;
1228         }
1229
1230         /**
1231          * Don't render the control content from PHP, as it's rendered via JS on load.
1232          *
1233          * @since 4.2.0
1234          * @access public
1235          */
1236         public function render_content() {}
1237
1238         /**
1239          * Render a JS template for theme display.
1240          *
1241          * @since 4.2.0
1242          * @access public
1243          */
1244         public function content_template() {
1245                 $current_url = set_url_scheme( 'http://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'] );
1246                 $active_url  = esc_url( remove_query_arg( 'theme', $current_url ) );
1247                 $preview_url = esc_url( add_query_arg( 'theme', '__THEME__', $current_url ) ); // Token because esc_url() strips curly braces.
1248                 $preview_url = str_replace( '__THEME__', '{{ data.theme.id }}', $preview_url );
1249                 ?>
1250                 <# if ( data.theme.isActiveTheme ) { #>
1251                         <div class="theme active" tabindex="0" data-preview-url="<?php echo esc_attr( $active_url ); ?>" aria-describedby="{{ data.theme.id }}-action {{ data.theme.id }}-name">
1252                 <# } else { #>
1253                         <div class="theme" tabindex="0" data-preview-url="<?php echo esc_attr( $preview_url ); ?>" aria-describedby="{{ data.theme.id }}-action {{ data.theme.id }}-name">
1254                 <# } #>
1255
1256                         <# if ( data.theme.screenshot[0] ) { #>
1257                                 <div class="theme-screenshot">
1258                                         <img data-src="{{ data.theme.screenshot[0] }}" alt="" />
1259                                 </div>
1260                         <# } else { #>
1261                                 <div class="theme-screenshot blank"></div>
1262                         <# } #>
1263
1264                         <# if ( data.theme.isActiveTheme ) { #>
1265                                 <span class="more-details" id="{{ data.theme.id }}-action"><?php _e( 'Customize' ); ?></span>
1266                         <# } else { #>
1267                                 <span class="more-details" id="{{ data.theme.id }}-action"><?php _e( 'Live Preview' ); ?></span>
1268                         <# } #>
1269
1270                         <div class="theme-author"><?php printf( __( 'By %s' ), '{{ data.theme.author }}' ); ?></div>
1271
1272                         <# if ( data.theme.isActiveTheme ) { #>
1273                                 <h3 class="theme-name" id="{{ data.theme.id }}-name">
1274                                         <?php
1275                                         /* translators: %s: theme name */
1276                                         printf( __( '<span>Active:</span> %s' ), '{{ data.theme.name }}' );
1277                                         ?>
1278                                 </h3>
1279                         <# } else { #>
1280                                 <h3 class="theme-name" id="{{ data.theme.id }}-name">{{ data.theme.name }}</h3>
1281                                 <div class="theme-actions">
1282                                         <button type="button" class="button theme-details"><?php _e( 'Theme Details' ); ?></button>
1283                                 </div>
1284                         <# } #>
1285                 </div>
1286         <?php
1287         }
1288 }
1289
1290 /**
1291  * Widget Area Customize Control class.
1292  *
1293  * @since 3.9.0
1294  *
1295  * @see WP_Customize_Control
1296  */
1297 class WP_Widget_Area_Customize_Control extends WP_Customize_Control {
1298         public $type = 'sidebar_widgets';
1299         public $sidebar_id;
1300
1301         public function to_json() {
1302                 parent::to_json();
1303                 $exported_properties = array( 'sidebar_id' );
1304                 foreach ( $exported_properties as $key ) {
1305                         $this->json[ $key ] = $this->$key;
1306                 }
1307         }
1308
1309         public function render_content() {
1310                 ?>
1311                 <span class="button-secondary add-new-widget" tabindex="0">
1312                         <?php _e( 'Add a Widget' ); ?>
1313                 </span>
1314
1315                 <span class="reorder-toggle" tabindex="0">
1316                         <span class="reorder"><?php _ex( 'Reorder', 'Reorder widgets in Customizer' ); ?></span>
1317                         <span class="reorder-done"><?php _ex( 'Done', 'Cancel reordering widgets in Customizer' ); ?></span>
1318                 </span>
1319                 <?php
1320         }
1321
1322 }
1323
1324 /**
1325  * Widget Form Customize Control class.
1326  *
1327  * @since 3.9.0
1328  *
1329  * @see WP_Customize_Control
1330  */
1331 class WP_Widget_Form_Customize_Control extends WP_Customize_Control {
1332         public $type = 'widget_form';
1333         public $widget_id;
1334         public $widget_id_base;
1335         public $sidebar_id;
1336         public $is_new = false;
1337         public $width;
1338         public $height;
1339         public $is_wide = false;
1340
1341         public function to_json() {
1342                 parent::to_json();
1343                 $exported_properties = array( 'widget_id', 'widget_id_base', 'sidebar_id', 'width', 'height', 'is_wide' );
1344                 foreach ( $exported_properties as $key ) {
1345                         $this->json[ $key ] = $this->$key;
1346                 }
1347         }
1348
1349         public function render_content() {
1350                 global $wp_registered_widgets;
1351                 require_once ABSPATH . '/wp-admin/includes/widgets.php';
1352
1353                 $widget = $wp_registered_widgets[ $this->widget_id ];
1354                 if ( ! isset( $widget['params'][0] ) ) {
1355                         $widget['params'][0] = array();
1356                 }
1357
1358                 $args = array(
1359                         'widget_id' => $widget['id'],
1360                         'widget_name' => $widget['name'],
1361                 );
1362
1363                 $args = wp_list_widget_controls_dynamic_sidebar( array( 0 => $args, 1 => $widget['params'][0] ) );
1364                 echo $this->manager->widgets->get_widget_control( $args );
1365         }
1366
1367         /**
1368          * Whether the current widget is rendered on the page.
1369          *
1370          * @since 4.0.0
1371          * @access public
1372          *
1373          * @return bool Whether the widget is rendered.
1374          */
1375         public function active_callback() {
1376                 return $this->manager->widgets->is_widget_rendered( $this->widget_id );
1377         }
1378 }