WordPress 4.3
[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          *
24          * @static
25          * @access protected
26          * @var int
27          */
28         protected static $instance_count = 0;
29
30         /**
31          * Order in which this instance was created in relation to other instances.
32          *
33          * @since 4.1.0
34          * @access public
35          * @var int
36          */
37         public $instance_number;
38
39         /**
40          * @access public
41          * @var WP_Customize_Manager
42          */
43         public $manager;
44
45         /**
46          * @access public
47          * @var string
48          */
49         public $id;
50
51         /**
52          * All settings tied to the control.
53          *
54          * @access public
55          * @var array
56          */
57         public $settings;
58
59         /**
60          * The primary setting for the control (if there is one).
61          *
62          * @access public
63          * @var string
64          */
65         public $setting = 'default';
66
67         /**
68          * @access public
69          * @var int
70          */
71         public $priority = 10;
72
73         /**
74          * @access public
75          * @var string
76          */
77         public $section = '';
78
79         /**
80          * @access public
81          * @var string
82          */
83         public $label = '';
84
85         /**
86          * @access public
87          * @var string
88          */
89         public $description = '';
90
91         /**
92          * @todo: Remove choices
93          *
94          * @access public
95          * @var array
96          */
97         public $choices = array();
98
99         /**
100          * @access public
101          * @var array
102          */
103         public $input_attrs = array();
104
105         /**
106          * @deprecated It is better to just call the json() method
107          * @access public
108          * @var array
109          */
110         public $json = array();
111
112         /**
113          * @access public
114          * @var string
115          */
116         public $type = 'text';
117
118         /**
119          * Callback.
120          *
121          * @since 4.0.0
122          * @access public
123          *
124          * @see WP_Customize_Control::active()
125          *
126          * @var callable Callback is called with one argument, the instance of
127          *               WP_Customize_Control, and returns bool to indicate whether
128          *               the control is active (such as it relates to the URL
129          *               currently being previewed).
130          */
131         public $active_callback = '';
132
133         /**
134          * Constructor.
135          *
136          * Supplied $args override class property defaults.
137          *
138          * If $args['settings'] is not defined, use the $id as the setting ID.
139          *
140          * @since 3.4.0
141          *
142          * @param WP_Customize_Manager $manager Customizer bootstrap instance.
143          * @param string               $id      Control ID.
144          * @param array                $args    Optional. Arguments to override class property defaults.
145          */
146         public function __construct( $manager, $id, $args = array() ) {
147                 $keys = array_keys( get_object_vars( $this ) );
148                 foreach ( $keys as $key ) {
149                         if ( isset( $args[ $key ] ) ) {
150                                 $this->$key = $args[ $key ];
151                         }
152                 }
153
154                 $this->manager = $manager;
155                 $this->id = $id;
156                 if ( empty( $this->active_callback ) ) {
157                         $this->active_callback = array( $this, 'active_callback' );
158                 }
159                 self::$instance_count += 1;
160                 $this->instance_number = self::$instance_count;
161
162                 // Process settings.
163                 if ( empty( $this->settings ) ) {
164                         $this->settings = $id;
165                 }
166
167                 $settings = array();
168                 if ( is_array( $this->settings ) ) {
169                         foreach ( $this->settings as $key => $setting ) {
170                                 $settings[ $key ] = $this->manager->get_setting( $setting );
171                         }
172                 } else {
173                         $this->setting = $this->manager->get_setting( $this->settings );
174                         $settings['default'] = $this->setting;
175                 }
176                 $this->settings = $settings;
177         }
178
179         /**
180          * Enqueue control related scripts/styles.
181          *
182          * @since 3.4.0
183          */
184         public function enqueue() {}
185
186         /**
187          * Check whether control is active to current Customizer preview.
188          *
189          * @since 4.0.0
190          * @access public
191          *
192          * @return bool Whether the control is active to the current preview.
193          */
194         final public function active() {
195                 $control = $this;
196                 $active = call_user_func( $this->active_callback, $this );
197
198                 /**
199                  * Filter response of WP_Customize_Control::active().
200                  *
201                  * @since 4.0.0
202                  *
203                  * @param bool                 $active  Whether the Customizer control is active.
204                  * @param WP_Customize_Control $control WP_Customize_Control instance.
205                  */
206                 $active = apply_filters( 'customize_control_active', $active, $control );
207
208                 return $active;
209         }
210
211         /**
212          * Default callback used when invoking WP_Customize_Control::active().
213          *
214          * Subclasses can override this with their specific logic, or they may
215          * provide an 'active_callback' argument to the constructor.
216          *
217          * @since 4.0.0
218          * @access public
219          *
220          * @return true Always true.
221          */
222         public function active_callback() {
223                 return true;
224         }
225
226         /**
227          * Fetch a setting's value.
228          * Grabs the main setting by default.
229          *
230          * @since 3.4.0
231          *
232          * @param string $setting_key
233          * @return mixed The requested setting's value, if the setting exists.
234          */
235         final public function value( $setting_key = 'default' ) {
236                 if ( isset( $this->settings[ $setting_key ] ) ) {
237                         return $this->settings[ $setting_key ]->value();
238                 }
239         }
240
241         /**
242          * Refresh the parameters passed to the JavaScript via JSON.
243          *
244          * @since 3.4.0
245          */
246         public function to_json() {
247                 $this->json['settings'] = array();
248                 foreach ( $this->settings as $key => $setting ) {
249                         $this->json['settings'][ $key ] = $setting->id;
250                 }
251
252                 $this->json['type'] = $this->type;
253                 $this->json['priority'] = $this->priority;
254                 $this->json['active'] = $this->active();
255                 $this->json['section'] = $this->section;
256                 $this->json['content'] = $this->get_content();
257                 $this->json['label'] = $this->label;
258                 $this->json['description'] = $this->description;
259                 $this->json['instanceNumber'] = $this->instance_number;
260         }
261
262         /**
263          * Get the data to export to the client via JSON.
264          *
265          * @since 4.1.0
266          *
267          * @return array Array of parameters passed to the JavaScript.
268          */
269         public function json() {
270                 $this->to_json();
271                 return $this->json;
272         }
273
274         /**
275          * Check if the theme supports the control and check user capabilities.
276          *
277          * @since 3.4.0
278          *
279          * @return bool False if theme doesn't support the control or user doesn't have the required permissions, otherwise true.
280          */
281         final public function check_capabilities() {
282                 foreach ( $this->settings as $setting ) {
283                         if ( ! $setting->check_capabilities() )
284                                 return false;
285                 }
286
287                 $section = $this->manager->get_section( $this->section );
288                 if ( isset( $section ) && ! $section->check_capabilities() )
289                         return false;
290
291                 return true;
292         }
293
294         /**
295          * Get the control's content for insertion into the Customizer pane.
296          *
297          * @since 4.1.0
298          *
299          * @return string Contents of the control.
300          */
301         final public function get_content() {
302                 ob_start();
303                 $this->maybe_render();
304                 return trim( ob_get_clean() );
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 Customizer bootstrap instance.
572          * @param string               $id      Control ID.
573          * @param array                $args    Optional. Arguments to override class property defaults.
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 Customizer bootstrap instance.
682          * @param string               $id      Control ID.
683          * @param array                $args    Optional. Arguments to override class property defaults.
684          */
685         public function __construct( $manager, $id, $args = array() ) {
686                 parent::__construct( $manager, $id, $args );
687
688                 $this->button_labels = array(
689                         'select'       => __( 'Select File' ),
690                         'change'       => __( 'Change File' ),
691                         'default'      => __( 'Default' ),
692                         'remove'       => __( 'Remove' ),
693                         'placeholder'  => __( 'No file selected' ),
694                         'frame_title'  => __( 'Select File' ),
695                         'frame_button' => __( 'Choose File' ),
696                 );
697         }
698
699         /**
700          * Enqueue control related scripts/styles.
701          *
702          * @since 3.4.0
703          * @since 4.2.0 Moved from WP_Customize_Upload_Control.
704          */
705         public function enqueue() {
706                 wp_enqueue_media();
707         }
708
709         /**
710          * Refresh the parameters passed to the JavaScript via JSON.
711          *
712          * @since 3.4.0
713          * @since 4.2.0 Moved from WP_Customize_Upload_Control.
714          *
715          * @see WP_Customize_Control::to_json()
716          */
717         public function to_json() {
718                 parent::to_json();
719                 $this->json['label'] = html_entity_decode( $this->label, ENT_QUOTES, get_bloginfo( 'charset' ) );
720                 $this->json['mime_type'] = $this->mime_type;
721                 $this->json['button_labels'] = $this->button_labels;
722                 $this->json['canUpload'] = current_user_can( 'upload_files' );
723
724                 $value = $this->value();
725
726                 if ( is_object( $this->setting ) ) {
727                         if ( $this->setting->default ) {
728                                 // Fake an attachment model - needs all fields used by template.
729                                 // Note that the default value must be a URL, NOT an attachment ID.
730                                 $type = in_array( substr( $this->setting->default, -3 ), array( 'jpg', 'png', 'gif', 'bmp' ) ) ? 'image' : 'document';
731                                 $default_attachment = array(
732                                         'id' => 1,
733                                         'url' => $this->setting->default,
734                                         'type' => $type,
735                                         'icon' => wp_mime_type_icon( $type ),
736                                         'title' => basename( $this->setting->default ),
737                                 );
738
739                                 if ( 'image' === $type ) {
740                                         $default_attachment['sizes'] = array(
741                                                 'full' => array( 'url' => $this->setting->default ),
742                                         );
743                                 }
744
745                                 $this->json['defaultAttachment'] = $default_attachment;
746                         }
747
748                         if ( $value && $this->setting->default && $value === $this->setting->default ) {
749                                 // Set the default as the attachment.
750                                 $this->json['attachment'] = $this->json['defaultAttachment'];
751                         } elseif ( $value ) {
752                                 $this->json['attachment'] = wp_prepare_attachment_for_js( $value );
753                         }
754                 }
755         }
756
757         /**
758          * Don't render any content for this control from PHP.
759          *
760          * @since 3.4.0
761          * @since 4.2.0 Moved from WP_Customize_Upload_Control.
762          *
763          * @see WP_Customize_Media_Control::content_template()
764          */
765         public function render_content() {}
766
767         /**
768          * Render a JS template for the content of the media control.
769          *
770          * @since 4.1.0
771          * @since 4.2.0 Moved from WP_Customize_Upload_Control.
772          */
773         public function content_template() {
774                 ?>
775                 <label for="{{ data.settings['default'] }}-button">
776                         <# if ( data.label ) { #>
777                                 <span class="customize-control-title">{{ data.label }}</span>
778                         <# } #>
779                         <# if ( data.description ) { #>
780                                 <span class="description customize-control-description">{{{ data.description }}}</span>
781                         <# } #>
782                 </label>
783
784                 <# if ( data.attachment && data.attachment.id ) { #>
785                         <div class="current">
786                                 <div class="container">
787                                         <div class="attachment-media-view attachment-media-view-{{ data.attachment.type }} {{ data.attachment.orientation }}">
788                                                 <div class="thumbnail thumbnail-{{ data.attachment.type }}">
789                                                         <# if ( 'image' === data.attachment.type && data.attachment.sizes && data.attachment.sizes.medium ) { #>
790                                                                 <img class="attachment-thumb" src="{{ data.attachment.sizes.medium.url }}" draggable="false" />
791                                                         <# } else if ( 'image' === data.attachment.type && data.attachment.sizes && data.attachment.sizes.full ) { #>
792                                                                 <img class="attachment-thumb" src="{{ data.attachment.sizes.full.url }}" draggable="false" />
793                                                         <# } else if ( 'audio' === data.attachment.type ) { #>
794                                                                 <# if ( data.attachment.image && data.attachment.image.src && data.attachment.image.src !== data.attachment.icon ) { #>
795                                                                         <img src="{{ data.attachment.image.src }}" class="thumbnail" draggable="false" />
796                                                                 <# } else { #>
797                                                                         <img src="{{ data.attachment.icon }}" class="attachment-thumb type-icon" draggable="false" />
798                                                                 <# } #>
799                                                                 <p class="attachment-meta attachment-meta-title">&#8220;{{ data.attachment.title }}&#8221;</p>
800                                                                 <# if ( data.attachment.album || data.attachment.meta.album ) { #>
801                                                                 <p class="attachment-meta"><em>{{ data.attachment.album || data.attachment.meta.album }}</em></p>
802                                                                 <# } #>
803                                                                 <# if ( data.attachment.artist || data.attachment.meta.artist ) { #>
804                                                                 <p class="attachment-meta">{{ data.attachment.artist || data.attachment.meta.artist }}</p>
805                                                                 <# } #>
806                                                                 <audio style="visibility: hidden" controls class="wp-audio-shortcode" width="100%" preload="none">
807                                                                         <source type="{{ data.attachment.mime }}" src="{{ data.attachment.url }}"/>
808                                                                 </audio>
809                                                         <# } else if ( 'video' === data.attachment.type ) { #>
810                                                                 <div class="wp-media-wrapper wp-video">
811                                                                         <video controls="controls" class="wp-video-shortcode" preload="metadata"
812                                                                                 <# if ( data.attachment.image && data.attachment.image.src !== data.attachment.icon ) { #>poster="{{ data.attachment.image.src }}"<# } #>>
813                                                                                 <source type="{{ data.attachment.mime }}" src="{{ data.attachment.url }}"/>
814                                                                         </video>
815                                                                 </div>
816                                                         <# } else { #>
817                                                                 <img class="attachment-thumb type-icon icon" src="{{ data.attachment.icon }}" draggable="false" />
818                                                                 <p class="attachment-title">{{ data.attachment.title }}</p>
819                                                         <# } #>
820                                                 </div>
821                                         </div>
822                                 </div>
823                         </div>
824                         <div class="actions">
825                                 <# if ( data.canUpload ) { #>
826                                 <button type="button" class="button remove-button"><?php echo $this->button_labels['remove']; ?></button>
827                                 <button type="button" class="button upload-button" id="{{ data.settings['default'] }}-button"><?php echo $this->button_labels['change']; ?></button>
828                                 <div style="clear:both"></div>
829                                 <# } #>
830                         </div>
831                 <# } else { #>
832                         <div class="current">
833                                 <div class="container">
834                                         <div class="placeholder">
835                                                 <div class="inner">
836                                                         <span>
837                                                                 <?php echo $this->button_labels['placeholder']; ?>
838                                                         </span>
839                                                 </div>
840                                         </div>
841                                 </div>
842                         </div>
843                         <div class="actions">
844                                 <# if ( data.defaultAttachment ) { #>
845                                         <button type="button" class="button default-button"><?php echo $this->button_labels['default']; ?></button>
846                                 <# } #>
847                                 <# if ( data.canUpload ) { #>
848                                 <button type="button" class="button upload-button" id="{{ data.settings['default'] }}-button"><?php echo $this->button_labels['select']; ?></button>
849                                 <# } #>
850                                 <div style="clear:both"></div>
851                         </div>
852                 <# } #>
853                 <?php
854         }
855 }
856
857 /**
858  * Customize Upload Control Class.
859  *
860  * @since 3.4.0
861  *
862  * @see WP_Customize_Media_Control
863  */
864 class WP_Customize_Upload_Control extends WP_Customize_Media_Control {
865         public $type          = 'upload';
866         public $mime_type     = '';
867         public $button_labels = array();
868         public $removed = ''; // unused
869         public $context; // unused
870         public $extensions = array(); // unused
871
872         /**
873          * Refresh the parameters passed to the JavaScript via JSON.
874          *
875          * @since 3.4.0
876          *
877          * @uses WP_Customize_Media_Control::to_json()
878          */
879         public function to_json() {
880                 parent::to_json();
881
882                 $value = $this->value();
883                 if ( $value ) {
884                         // Get the attachment model for the existing file.
885                         $attachment_id = attachment_url_to_postid( $value );
886                         if ( $attachment_id ) {
887                                 $this->json['attachment'] = wp_prepare_attachment_for_js( $attachment_id );
888                         }
889                 }
890         }
891 }
892
893 /**
894  * Customize Image Control class.
895  *
896  * @since 3.4.0
897  *
898  * @see WP_Customize_Upload_Control
899  */
900 class WP_Customize_Image_Control extends WP_Customize_Upload_Control {
901         public $type = 'image';
902         public $mime_type = 'image';
903
904         /**
905          * Constructor.
906          *
907          * @since 3.4.0
908          * @uses WP_Customize_Upload_Control::__construct()
909          *
910          * @param WP_Customize_Manager $manager Customizer bootstrap instance.
911          * @param string               $id      Control ID.
912          * @param array                $args    Optional. Arguments to override class property defaults.
913          */
914         public function __construct( $manager, $id, $args = array() ) {
915                 parent::__construct( $manager, $id, $args );
916
917                 $this->button_labels = array(
918                         'select'       => __( 'Select Image' ),
919                         'change'       => __( 'Change Image' ),
920                         'remove'       => __( 'Remove' ),
921                         'default'      => __( 'Default' ),
922                         'placeholder'  => __( 'No image selected' ),
923                         'frame_title'  => __( 'Select Image' ),
924                         'frame_button' => __( 'Choose Image' ),
925                 );
926         }
927
928         /**
929          * @since 3.4.2
930          * @deprecated 4.1.0
931          */
932         public function prepare_control() {}
933
934         /**
935          * @since 3.4.0
936          * @deprecated 4.1.0
937          *
938          * @param string $id
939          * @param string $label
940          * @param mixed $callback
941          */
942         public function add_tab( $id, $label, $callback ) {}
943
944         /**
945          * @since 3.4.0
946          * @deprecated 4.1.0
947          *
948          * @param string $id
949          */
950         public function remove_tab( $id ) {}
951
952         /**
953          * @since 3.4.0
954          * @deprecated 4.1.0
955          *
956          * @param string $url
957          * @param string $thumbnail_url
958          */
959         public function print_tab_image( $url, $thumbnail_url = null ) {}
960 }
961
962 /**
963  * Customize Background Image Control class.
964  *
965  * @since 3.4.0
966  *
967  * @see WP_Customize_Image_Control
968  */
969 class WP_Customize_Background_Image_Control extends WP_Customize_Image_Control {
970         public $type = 'background';
971
972         /**
973          * Constructor.
974          *
975          * @since 3.4.0
976          * @uses WP_Customize_Image_Control::__construct()
977          *
978          * @param WP_Customize_Manager $manager Customizer bootstrap instance.
979          */
980         public function __construct( $manager ) {
981                 parent::__construct( $manager, 'background_image', array(
982                         'label'    => __( 'Background Image' ),
983                         'section'  => 'background_image',
984                 ) );
985         }
986
987         /**
988          * Enqueue control related scripts/styles.
989          *
990          * @since 4.1.0
991          */
992         public function enqueue() {
993                 parent::enqueue();
994
995                 wp_localize_script( 'customize-controls', '_wpCustomizeBackground', array(
996                         'nonces' => array(
997                                 'add' => wp_create_nonce( 'background-add' ),
998                         ),
999                 ) );
1000         }
1001 }
1002
1003 /**
1004  * Customize Cropped Image Control class.
1005  *
1006  * @since 4.3.0
1007  *
1008  * @see WP_Customize_Media_Control
1009  */
1010 class WP_Customize_Cropped_Image_Control extends WP_Customize_Media_Control {
1011
1012         /**
1013          * Control type.
1014          *
1015          * @since 4.3.0
1016          * @access public
1017          * @var string
1018          */
1019         public $type = 'cropped_image';
1020
1021         /**
1022          * Suggested width for cropped image.
1023          *
1024          * @since 4.3.0
1025          * @access public
1026          * @var int
1027          */
1028         public $width = 150;
1029
1030         /**
1031          * Suggested height for cropped image.
1032          *
1033          * @since 4.3.0
1034          * @access public
1035          * @var int
1036          */
1037         public $height = 150;
1038
1039         /**
1040          * Whether the width is flexible.
1041          *
1042          * @since 4.3.0
1043          * @access public
1044          * @var bool
1045          */
1046         public $flex_width = false;
1047
1048         /**
1049          * Whether the height is flexible.
1050          *
1051          * @since 4.3.0
1052          * @access public
1053          * @var bool
1054          */
1055         public $flex_height = false;
1056
1057         /**
1058          * Enqueue control related scripts/styles.
1059          *
1060          * @since 4.3.0
1061          * @access public
1062          */
1063         public function enqueue() {
1064                 wp_enqueue_script( 'customize-views' );
1065
1066                 parent::enqueue();
1067         }
1068
1069         /**
1070          * Refresh the parameters passed to the JavaScript via JSON.
1071          *
1072          * @since 4.3.0
1073          * @access public
1074          *
1075          * @see WP_Customize_Control::to_json()
1076          */
1077         public function to_json() {
1078                 parent::to_json();
1079
1080                 $this->json['width']       = absint( $this->width );
1081                 $this->json['height']      = absint( $this->height );
1082                 $this->json['flex_width']  = absint( $this->flex_width );
1083                 $this->json['flex_height'] = absint( $this->flex_height );
1084         }
1085
1086 }
1087
1088 /**
1089  * Customize Site Icon control class.
1090  *
1091  * Used only for custom functionality in JavaScript.
1092  *
1093  * @since 4.3.0
1094  *
1095  * @see WP_Customize_Cropped_Image_Control
1096  */
1097 class WP_Customize_Site_Icon_Control extends WP_Customize_Cropped_Image_Control {
1098
1099         /**
1100          * Control type.
1101          *
1102          * @since 4.3.0
1103          * @access public
1104          * @var string
1105          */
1106         public $type = 'site_icon';
1107
1108         /**
1109          * Constructor.
1110          *
1111          * @since 4.3.0
1112          * @access public
1113          *
1114          * @param WP_Customize_Manager $manager Customizer bootstrap instance.
1115          * @param string               $id      Control ID.
1116          * @param array                $args    Optional. Arguments to override class property defaults.
1117          */
1118         public function __construct( $manager, $id, $args = array() ) {
1119                 parent::__construct( $manager, $id, $args );
1120                 add_action( 'customize_controls_print_styles', 'wp_site_icon', 99 );
1121         }
1122 }
1123
1124 /**
1125  * Customize Header Image Control class.
1126  *
1127  * @since 3.4.0
1128  *
1129  * @see WP_Customize_Image_Control
1130  */
1131 class WP_Customize_Header_Image_Control extends WP_Customize_Image_Control {
1132         public $type = 'header';
1133         public $uploaded_headers;
1134         public $default_headers;
1135
1136         /**
1137          * Constructor.
1138          *
1139          * @since 3.4.0
1140          *
1141          * @param WP_Customize_Manager $manager Customizer bootstrap instance.
1142          */
1143         public function __construct( $manager ) {
1144                 parent::__construct( $manager, 'header_image', array(
1145                         'label'    => __( 'Header Image' ),
1146                         'settings' => array(
1147                                 'default' => 'header_image',
1148                                 'data'    => 'header_image_data',
1149                         ),
1150                         'section'  => 'header_image',
1151                         'removed'  => 'remove-header',
1152                         'get_url'  => 'get_header_image',
1153                 ) );
1154
1155         }
1156
1157         /**
1158          * @access public
1159          */
1160         public function enqueue() {
1161                 wp_enqueue_media();
1162                 wp_enqueue_script( 'customize-views' );
1163
1164                 $this->prepare_control();
1165
1166                 wp_localize_script( 'customize-views', '_wpCustomizeHeader', array(
1167                         'data' => array(
1168                                 'width' => absint( get_theme_support( 'custom-header', 'width' ) ),
1169                                 'height' => absint( get_theme_support( 'custom-header', 'height' ) ),
1170                                 'flex-width' => absint( get_theme_support( 'custom-header', 'flex-width' ) ),
1171                                 'flex-height' => absint( get_theme_support( 'custom-header', 'flex-height' ) ),
1172                                 'currentImgSrc' => $this->get_current_image_src(),
1173                         ),
1174                         'nonces' => array(
1175                                 'add' => wp_create_nonce( 'header-add' ),
1176                                 'remove' => wp_create_nonce( 'header-remove' ),
1177                         ),
1178                         'uploads' => $this->uploaded_headers,
1179                         'defaults' => $this->default_headers
1180                 ) );
1181
1182                 parent::enqueue();
1183         }
1184
1185         /**
1186          *
1187          * @global Custom_Image_Header $custom_image_header
1188          */
1189         public function prepare_control() {
1190                 global $custom_image_header;
1191                 if ( empty( $custom_image_header ) ) {
1192                         return;
1193                 }
1194
1195                 // Process default headers and uploaded headers.
1196                 $custom_image_header->process_default_headers();
1197                 $this->default_headers = $custom_image_header->get_default_header_images();
1198                 $this->uploaded_headers = $custom_image_header->get_uploaded_header_images();
1199         }
1200
1201         /**
1202          * @access public
1203          */
1204         public function print_header_image_template() {
1205                 ?>
1206                 <script type="text/template" id="tmpl-header-choice">
1207                         <# if (data.random) { #>
1208                         <button type="button" class="button display-options random">
1209                                 <span class="dashicons dashicons-randomize dice"></span>
1210                                 <# if ( data.type === 'uploaded' ) { #>
1211                                         <?php _e( 'Randomize uploaded headers' ); ?>
1212                                 <# } else if ( data.type === 'default' ) { #>
1213                                         <?php _e( 'Randomize suggested headers' ); ?>
1214                                 <# } #>
1215                         </button>
1216
1217                         <# } else { #>
1218
1219                         <# if (data.type === 'uploaded') { #>
1220                                 <button type="button" class="dashicons dashicons-no close"><span class="screen-reader-text"><?php _e( 'Remove image' ); ?></span></button>
1221                         <# } #>
1222
1223                         <button type="button" class="choice thumbnail"
1224                                 data-customize-image-value="{{{data.header.url}}}"
1225                                 data-customize-header-image-data="{{JSON.stringify(data.header)}}">
1226                                 <span class="screen-reader-text"><?php _e( 'Set image' ); ?></span>
1227                                 <img src="{{{data.header.thumbnail_url}}}" alt="{{{data.header.alt_text || data.header.description}}}">
1228                         </button>
1229
1230                         <# } #>
1231                 </script>
1232
1233                 <script type="text/template" id="tmpl-header-current">
1234                         <# if (data.choice) { #>
1235                                 <# if (data.random) { #>
1236
1237                         <div class="placeholder">
1238                                 <div class="inner">
1239                                         <span><span class="dashicons dashicons-randomize dice"></span>
1240                                         <# if ( data.type === 'uploaded' ) { #>
1241                                                 <?php _e( 'Randomizing uploaded headers' ); ?>
1242                                         <# } else if ( data.type === 'default' ) { #>
1243                                                 <?php _e( 'Randomizing suggested headers' ); ?>
1244                                         <# } #>
1245                                         </span>
1246                                 </div>
1247                         </div>
1248
1249                                 <# } else { #>
1250
1251                         <img src="{{{data.header.thumbnail_url}}}" alt="{{{data.header.alt_text || data.header.description}}}" tabindex="0"/>
1252
1253                                 <# } #>
1254                         <# } else { #>
1255
1256                         <div class="placeholder">
1257                                 <div class="inner">
1258                                         <span>
1259                                                 <?php _e( 'No image set' ); ?>
1260                                         </span>
1261                                 </div>
1262                         </div>
1263
1264                         <# } #>
1265                 </script>
1266                 <?php
1267         }
1268
1269         /**
1270          * @return string|void
1271          */
1272         public function get_current_image_src() {
1273                 $src = $this->value();
1274                 if ( isset( $this->get_url ) ) {
1275                         $src = call_user_func( $this->get_url, $src );
1276                         return $src;
1277                 }
1278         }
1279
1280         /**
1281          * @access public
1282          */
1283         public function render_content() {
1284                 $this->print_header_image_template();
1285                 $visibility = $this->get_current_image_src() ? '' : ' style="display:none" ';
1286                 $width = absint( get_theme_support( 'custom-header', 'width' ) );
1287                 $height = absint( get_theme_support( 'custom-header', 'height' ) );
1288                 ?>
1289                 <div class="customize-control-content">
1290                         <p class="customizer-section-intro">
1291                                 <?php
1292                                 if ( $width && $height ) {
1293                                         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 );
1294                                 } elseif ( $width ) {
1295                                         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 );
1296                                 } else {
1297                                         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 );
1298                                 }
1299                                 ?>
1300                         </p>
1301                         <div class="current">
1302                                 <span class="customize-control-title">
1303                                         <?php _e( 'Current header' ); ?>
1304                                 </span>
1305                                 <div class="container">
1306                                 </div>
1307                         </div>
1308                         <div class="actions">
1309                                 <?php if ( current_user_can( 'upload_files' ) ): ?>
1310                                 <button type="button"<?php echo $visibility; ?> class="button remove" aria-label="<?php esc_attr_e( 'Hide header image' ); ?>"><?php _e( 'Hide image' ); ?></button>
1311                                 <button type="button" class="button new" aria-label="<?php esc_attr_e( 'Add new header image' ); ?>"><?php _e( 'Add new image' ); ?></button>
1312                                 <div style="clear:both"></div>
1313                                 <?php endif; ?>
1314                         </div>
1315                         <div class="choices">
1316                                 <span class="customize-control-title header-previously-uploaded">
1317                                         <?php _ex( 'Previously uploaded', 'custom headers' ); ?>
1318                                 </span>
1319                                 <div class="uploaded">
1320                                         <div class="list">
1321                                         </div>
1322                                 </div>
1323                                 <span class="customize-control-title header-default">
1324                                         <?php _ex( 'Suggested', 'custom headers' ); ?>
1325                                 </span>
1326                                 <div class="default">
1327                                         <div class="list">
1328                                         </div>
1329                                 </div>
1330                         </div>
1331                 </div>
1332                 <?php
1333         }
1334 }
1335
1336 /**
1337  * Customize Theme Control class.
1338  *
1339  * @since 4.2.0
1340  *
1341  * @see WP_Customize_Control
1342  */
1343 class WP_Customize_Theme_Control extends WP_Customize_Control {
1344
1345         /**
1346          * Customize control type.
1347          *
1348          * @since 4.2.0
1349          * @access public
1350          * @var string
1351          */
1352         public $type = 'theme';
1353
1354         /**
1355          * Theme object.
1356          *
1357          * @since 4.2.0
1358          * @access public
1359          * @var WP_Theme
1360          */
1361         public $theme;
1362
1363         /**
1364          * Refresh the parameters passed to the JavaScript via JSON.
1365          *
1366          * @since 4.2.0
1367          * @access public
1368          *
1369          * @see WP_Customize_Control::to_json()
1370          */
1371         public function to_json() {
1372                 parent::to_json();
1373                 $this->json['theme'] = $this->theme;
1374         }
1375
1376         /**
1377          * Don't render the control content from PHP, as it's rendered via JS on load.
1378          *
1379          * @since 4.2.0
1380          * @access public
1381          */
1382         public function render_content() {}
1383
1384         /**
1385          * Render a JS template for theme display.
1386          *
1387          * @since 4.2.0
1388          * @access public
1389          */
1390         public function content_template() {
1391                 $current_url = set_url_scheme( 'http://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'] );
1392                 $active_url  = esc_url( remove_query_arg( 'theme', $current_url ) );
1393                 $preview_url = esc_url( add_query_arg( 'theme', '__THEME__', $current_url ) ); // Token because esc_url() strips curly braces.
1394                 $preview_url = str_replace( '__THEME__', '{{ data.theme.id }}', $preview_url );
1395                 ?>
1396                 <# if ( data.theme.isActiveTheme ) { #>
1397                         <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">
1398                 <# } else { #>
1399                         <div class="theme" tabindex="0" data-preview-url="<?php echo esc_attr( $preview_url ); ?>" aria-describedby="{{ data.theme.id }}-action {{ data.theme.id }}-name">
1400                 <# } #>
1401
1402                         <# if ( data.theme.screenshot[0] ) { #>
1403                                 <div class="theme-screenshot">
1404                                         <img data-src="{{ data.theme.screenshot[0] }}" alt="" />
1405                                 </div>
1406                         <# } else { #>
1407                                 <div class="theme-screenshot blank"></div>
1408                         <# } #>
1409
1410                         <# if ( data.theme.isActiveTheme ) { #>
1411                                 <span class="more-details" id="{{ data.theme.id }}-action"><?php _e( 'Customize' ); ?></span>
1412                         <# } else { #>
1413                                 <span class="more-details" id="{{ data.theme.id }}-action"><?php _e( 'Live Preview' ); ?></span>
1414                         <# } #>
1415
1416                         <div class="theme-author"><?php printf( __( 'By %s' ), '{{ data.theme.author }}' ); ?></div>
1417
1418                         <# if ( data.theme.isActiveTheme ) { #>
1419                                 <h3 class="theme-name" id="{{ data.theme.id }}-name">
1420                                         <?php
1421                                         /* translators: %s: theme name */
1422                                         printf( __( '<span>Active:</span> %s' ), '{{{ data.theme.name }}}' );
1423                                         ?>
1424                                 </h3>
1425                         <# } else { #>
1426                                 <h3 class="theme-name" id="{{ data.theme.id }}-name">{{{ data.theme.name }}}</h3>
1427                                 <div class="theme-actions">
1428                                         <button type="button" class="button theme-details"><?php _e( 'Theme Details' ); ?></button>
1429                                 </div>
1430                         <# } #>
1431                 </div>
1432         <?php
1433         }
1434 }
1435
1436 /**
1437  * Widget Area Customize Control class.
1438  *
1439  * @since 3.9.0
1440  *
1441  * @see WP_Customize_Control
1442  */
1443 class WP_Widget_Area_Customize_Control extends WP_Customize_Control {
1444         public $type = 'sidebar_widgets';
1445         public $sidebar_id;
1446
1447         public function to_json() {
1448                 parent::to_json();
1449                 $exported_properties = array( 'sidebar_id' );
1450                 foreach ( $exported_properties as $key ) {
1451                         $this->json[ $key ] = $this->$key;
1452                 }
1453         }
1454
1455         /**
1456          * @access public
1457          */
1458         public function render_content() {
1459                 ?>
1460                 <span class="button-secondary add-new-widget" tabindex="0">
1461                         <?php _e( 'Add a Widget' ); ?>
1462                 </span>
1463
1464                 <span class="reorder-toggle" tabindex="0">
1465                         <span class="reorder"><?php _ex( 'Reorder', 'Reorder widgets in Customizer' ); ?></span>
1466                         <span class="reorder-done"><?php _ex( 'Done', 'Cancel reordering widgets in Customizer' ); ?></span>
1467                 </span>
1468                 <?php
1469         }
1470
1471 }
1472
1473 /**
1474  * Widget Form Customize Control class.
1475  *
1476  * @since 3.9.0
1477  *
1478  * @see WP_Customize_Control
1479  */
1480 class WP_Widget_Form_Customize_Control extends WP_Customize_Control {
1481         public $type = 'widget_form';
1482         public $widget_id;
1483         public $widget_id_base;
1484         public $sidebar_id;
1485         public $is_new = false;
1486         public $width;
1487         public $height;
1488         public $is_wide = false;
1489
1490         public function to_json() {
1491                 parent::to_json();
1492                 $exported_properties = array( 'widget_id', 'widget_id_base', 'sidebar_id', 'width', 'height', 'is_wide' );
1493                 foreach ( $exported_properties as $key ) {
1494                         $this->json[ $key ] = $this->$key;
1495                 }
1496         }
1497
1498         /**
1499          *
1500          * @global array $wp_registered_widgets
1501          */
1502         public function render_content() {
1503                 global $wp_registered_widgets;
1504                 require_once ABSPATH . '/wp-admin/includes/widgets.php';
1505
1506                 $widget = $wp_registered_widgets[ $this->widget_id ];
1507                 if ( ! isset( $widget['params'][0] ) ) {
1508                         $widget['params'][0] = array();
1509                 }
1510
1511                 $args = array(
1512                         'widget_id' => $widget['id'],
1513                         'widget_name' => $widget['name'],
1514                 );
1515
1516                 $args = wp_list_widget_controls_dynamic_sidebar( array( 0 => $args, 1 => $widget['params'][0] ) );
1517                 echo $this->manager->widgets->get_widget_control( $args );
1518         }
1519
1520         /**
1521          * Whether the current widget is rendered on the page.
1522          *
1523          * @since 4.0.0
1524          * @access public
1525          *
1526          * @return bool Whether the widget is rendered.
1527          */
1528         public function active_callback() {
1529                 return $this->manager->widgets->is_widget_rendered( $this->widget_id );
1530         }
1531 }
1532
1533 /**
1534  * Customize Nav Menu Control Class.
1535  *
1536  * @since 4.3.0
1537  */
1538 class WP_Customize_Nav_Menu_Control extends WP_Customize_Control {
1539
1540         /**
1541          * Control type.
1542          *
1543          * @since 4.3.0
1544          * @access public
1545          * @var string
1546          */
1547         public $type = 'nav_menu';
1548
1549         /**
1550          * The nav menu setting.
1551          *
1552          * @since 4.3.0
1553          * @access public
1554          * @var WP_Customize_Nav_Menu_Setting
1555          */
1556         public $setting;
1557
1558         /**
1559          * Don't render the control's content - it uses a JS template instead.
1560          *
1561          * @since 4.3.0
1562          * @access public
1563          */
1564         public function render_content() {}
1565
1566         /**
1567          * JS/Underscore template for the control UI.
1568          *
1569          * @since 4.3.0
1570          * @access public
1571          */
1572         public function content_template() {
1573                 ?>
1574                 <button type="button" class="button-secondary add-new-menu-item" aria-label="<?php esc_attr_e( 'Add or remove menu items' ); ?>" aria-expanded="false" aria-controls="available-menu-items">
1575                         <?php _e( 'Add Items' ); ?>
1576                 </button>
1577                 <button type="button" class="not-a-button reorder-toggle" aria-label="<?php esc_attr_e( 'Reorder menu items' ); ?>" aria-describedby="reorder-items-desc-{{ data.menu_id }}">
1578                         <span class="reorder"><?php _ex( 'Reorder', 'Reorder menu items in Customizer' ); ?></span>
1579                         <span class="reorder-done"><?php _ex( 'Done', 'Cancel reordering menu items in Customizer' ); ?></span>
1580                 </button>
1581                 <p class="screen-reader-text" id="reorder-items-desc-{{ data.menu_id }}"><?php _e( 'When in reorder mode, additional controls to reorder menu items will be available in the items list above.' ); ?></p>
1582                 <span class="add-menu-item-loading spinner"></span>
1583                 <span class="menu-delete-item">
1584                         <button type="button" class="not-a-button menu-delete">
1585                                 <?php _e( 'Delete menu' ); ?> <span class="screen-reader-text">{{ data.menu_name }}</span>
1586                         </button>
1587                 </span>
1588                 <?php if ( current_theme_supports( 'menus' ) ) : ?>
1589                 <ul class="menu-settings">
1590                         <li class="customize-control">
1591                                 <span class="customize-control-title"><?php _e( 'Menu locations' ); ?></span>
1592                         </li>
1593
1594                         <?php foreach ( get_registered_nav_menus() as $location => $description ) : ?>
1595                         <li class="customize-control customize-control-checkbox assigned-menu-location">
1596                                 <label>
1597                                         <input type="checkbox" data-menu-id="{{ data.menu_id }}" data-location-id="<?php echo esc_attr( $location ); ?>" class="menu-location" /> <?php echo $description; ?>
1598                                         <span class="theme-location-set"><?php printf( _x( '(Current: %s)', 'Current menu location' ), '<span class="current-menu-location-name-' . esc_attr( $location ) . '"></span>' ); ?></span>
1599                                 </label>
1600                         </li>
1601                         <?php endforeach; ?>
1602
1603                 </ul>
1604                 <?php endif;
1605         }
1606
1607         /**
1608          * Return parameters for this control.
1609          *
1610          * @since 4.3.0
1611          * @access public
1612          *
1613          * @return array Exported parameters.
1614          */
1615         public function json() {
1616                 $exported            = parent::json();
1617                 $exported['menu_id'] = $this->setting->term_id;
1618
1619                 return $exported;
1620         }
1621 }
1622
1623 /**
1624  * Customize control to represent the name field for a given menu.
1625  *
1626  * @since 4.3.0
1627  */
1628 class WP_Customize_Nav_Menu_Item_Control extends WP_Customize_Control {
1629
1630         /**
1631          * Control type.
1632          *
1633          * @since 4.3.0
1634          * @access public
1635          * @var string
1636          */
1637         public $type = 'nav_menu_item';
1638
1639         /**
1640          * The nav menu item setting.
1641          *
1642          * @since 4.3.0
1643          * @access public
1644          * @var WP_Customize_Nav_Menu_Item_Setting
1645          */
1646         public $setting;
1647
1648         /**
1649          * Constructor.
1650          *
1651          * @since 4.3.0
1652          * @access public
1653          *
1654          * @see WP_Customize_Control::__construct()
1655          *
1656          * @param WP_Customize_Manager $manager Customizer bootstrap instance.
1657          * @param string               $id      The control ID.
1658          * @param array                $args    Optional. Overrides class property defaults.
1659          */
1660         public function __construct( $manager, $id, $args = array() ) {
1661                 parent::__construct( $manager, $id, $args );
1662         }
1663
1664         /**
1665          * Don't render the control's content - it's rendered with a JS template.
1666          *
1667          * @since 4.3.0
1668          * @access public
1669          */
1670         public function render_content() {}
1671
1672         /**
1673          * JS/Underscore template for the control UI.
1674          *
1675          * @since 4.3.0
1676          * @access public
1677          */
1678         public function content_template() {
1679                 ?>
1680                 <div class="menu-item-bar">
1681                         <div class="menu-item-handle">
1682                                 <span class="item-type" aria-hidden="true">{{ data.item_type_label }}</span>
1683                                 <span class="item-title" aria-hidden="true">
1684                                         <span class="spinner"></span>
1685                                         <span class="menu-item-title<# if ( ! data.title ) { #> no-title<# } #>">{{ data.title || wp.customize.Menus.data.l10n.untitled }}</span>
1686                                 </span>
1687                                 <span class="item-controls">
1688                                         <button type="button" class="not-a-button item-edit" aria-expanded="false"><span class="screen-reader-text"><?php
1689                                                 /* translators: 1: Title of a menu item, 2: Type of a menu item */
1690                                                 printf( __( 'Edit menu item: %1$s (%2$s)' ), '{{ data.title || wp.customize.Menus.data.l10n.untitled }}', '{{ data.item_type_label }}' );
1691                                         ?></span><span class="toggle-indicator" aria-hidden="true"></span></button>
1692                                         <button type="button" class="not-a-button item-delete submitdelete deletion"><span class="screen-reader-text"><?php
1693                                                 /* translators: 1: Title of a menu item, 2: Type of a menu item */
1694                                                 printf( __( 'Remove Menu Item: %1$s (%2$s)' ), '{{ data.title || wp.customize.Menus.data.l10n.untitled }}', '{{ data.item_type_label }}' );
1695                                         ?></span></button>
1696                                 </span>
1697                         </div>
1698                 </div>
1699
1700                 <div class="menu-item-settings" id="menu-item-settings-{{ data.menu_item_id }}">
1701                         <# if ( 'custom' === data.item_type ) { #>
1702                         <p class="field-url description description-thin">
1703                                 <label for="edit-menu-item-url-{{ data.menu_item_id }}">
1704                                         <?php _e( 'URL' ); ?><br />
1705                                         <input class="widefat code edit-menu-item-url" type="text" id="edit-menu-item-url-{{ data.menu_item_id }}" name="menu-item-url" />
1706                                 </label>
1707                         </p>
1708                 <# } #>
1709                         <p class="description description-thin">
1710                                 <label for="edit-menu-item-title-{{ data.menu_item_id }}">
1711                                         <?php _e( 'Navigation Label' ); ?><br />
1712                                         <input type="text" id="edit-menu-item-title-{{ data.menu_item_id }}" class="widefat edit-menu-item-title" name="menu-item-title" />
1713                                 </label>
1714                         </p>
1715                         <p class="field-link-target description description-thin">
1716                                 <label for="edit-menu-item-target-{{ data.menu_item_id }}">
1717                                         <input type="checkbox" id="edit-menu-item-target-{{ data.menu_item_id }}" class="edit-menu-item-target" value="_blank" name="menu-item-target" />
1718                                         <?php _e( 'Open link in a new tab' ); ?>
1719                                 </label>
1720                         </p>
1721                         <p class="field-attr-title description description-thin">
1722                                 <label for="edit-menu-item-attr-title-{{ data.menu_item_id }}">
1723                                         <?php _e( 'Title Attribute' ); ?><br />
1724                                         <input type="text" id="edit-menu-item-attr-title-{{ data.menu_item_id }}" class="widefat edit-menu-item-attr-title" name="menu-item-attr-title" />
1725                                 </label>
1726                         </p>
1727                         <p class="field-css-classes description description-thin">
1728                                 <label for="edit-menu-item-classes-{{ data.menu_item_id }}">
1729                                         <?php _e( 'CSS Classes' ); ?><br />
1730                                         <input type="text" id="edit-menu-item-classes-{{ data.menu_item_id }}" class="widefat code edit-menu-item-classes" name="menu-item-classes" />
1731                                 </label>
1732                         </p>
1733                         <p class="field-xfn description description-thin">
1734                                 <label for="edit-menu-item-xfn-{{ data.menu_item_id }}">
1735                                         <?php _e( 'Link Relationship (XFN)' ); ?><br />
1736                                         <input type="text" id="edit-menu-item-xfn-{{ data.menu_item_id }}" class="widefat code edit-menu-item-xfn" name="menu-item-xfn" />
1737                                 </label>
1738                         </p>
1739                         <p class="field-description description description-thin">
1740                                 <label for="edit-menu-item-description-{{ data.menu_item_id }}">
1741                                         <?php _e( 'Description' ); ?><br />
1742                                         <textarea id="edit-menu-item-description-{{ data.menu_item_id }}" class="widefat edit-menu-item-description" rows="3" cols="20" name="menu-item-description">{{ data.description }}</textarea>
1743                                         <span class="description"><?php _e( 'The description will be displayed in the menu if the current theme supports it.' ); ?></span>
1744                                 </label>
1745                         </p>
1746
1747                         <div class="menu-item-actions description-thin submitbox">
1748                                 <# if ( ( 'post_type' === data.item_type || 'taxonomy' === data.item_type ) && '' !== data.original_title ) { #>
1749                                 <p class="link-to-original">
1750                                         <?php printf( __( 'Original: %s' ), '<a class="original-link" href="{{ data.url }}">{{ data.original_title }}</a>' ); ?>
1751                                 </p>
1752                                 <# } #>
1753
1754                                 <button type="button" class="not-a-button item-delete submitdelete deletion"><?php _e( 'Remove' ); ?></button>
1755                                 <span class="spinner"></span>
1756                         </div>
1757                         <input type="hidden" name="menu-item-db-id[{{ data.menu_item_id }}]" class="menu-item-data-db-id" value="{{ data.menu_item_id }}" />
1758                         <input type="hidden" name="menu-item-parent-id[{{ data.menu_item_id }}]" class="menu-item-data-parent-id" value="{{ data.parent }}" />
1759                 </div><!-- .menu-item-settings-->
1760                 <ul class="menu-item-transport"></ul>
1761                 <?php
1762         }
1763
1764         /**
1765          * Return parameters for this control.
1766          *
1767          * @since 4.3.0
1768          * @access public
1769          *
1770          * @return array Exported parameters.
1771          */
1772         public function json() {
1773                 $exported                 = parent::json();
1774                 $exported['menu_item_id'] = $this->setting->post_id;
1775
1776                 return $exported;
1777         }
1778 }
1779
1780 /**
1781  * Customize Menu Location Control Class.
1782  *
1783  * This custom control is only needed for JS.
1784  *
1785  * @since 4.3.0
1786  *
1787  * @see WP_Customize_Control
1788  */
1789 class WP_Customize_Nav_Menu_Location_Control extends WP_Customize_Control {
1790
1791         /**
1792          * Control type.
1793          *
1794          * @since 4.3.0
1795          * @access public
1796          * @var string
1797          */
1798         public $type = 'nav_menu_location';
1799
1800         /**
1801          * Location ID.
1802          *
1803          * @since 4.3.0
1804          * @access public
1805          * @var string
1806          */
1807         public $location_id = '';
1808
1809         /**
1810          * Refresh the parameters passed to JavaScript via JSON.
1811          *
1812          * @since 4.3.0
1813          * @access public
1814          *
1815          * @see WP_Customize_Control::to_json()
1816          */
1817         public function to_json() {
1818                 parent::to_json();
1819                 $this->json['locationId'] = $this->location_id;
1820         }
1821
1822         /**
1823          * Render content just like a normal select control.
1824          *
1825          * @since 4.3.0
1826          * @access public
1827          */
1828         public function render_content() {
1829                 if ( empty( $this->choices ) ) {
1830                         return;
1831                 }
1832                 ?>
1833                 <label>
1834                         <?php if ( ! empty( $this->label ) ) : ?>
1835                         <span class="customize-control-title"><?php echo esc_html( $this->label ); ?></span>
1836                         <?php endif; ?>
1837
1838                         <?php if ( ! empty( $this->description ) ) : ?>
1839                         <span class="description customize-control-description"><?php echo $this->description; ?></span>
1840                         <?php endif; ?>
1841
1842                         <select <?php $this->link(); ?>>
1843                                 <?php
1844                                 foreach ( $this->choices as $value => $label ) :
1845                                         echo '<option value="' . esc_attr( $value ) . '"' . selected( $this->value(), $value, false ) . '>' . $label . '</option>';
1846                                 endforeach;
1847                                 ?>
1848                         </select>
1849                 </label>
1850                 <?php
1851         }
1852 }
1853
1854 /**
1855  * Customize control to represent the name field for a given menu.
1856  *
1857  * @since 4.3.0
1858  *
1859  * @see WP_Customize_Control
1860  */
1861 class WP_Customize_Nav_Menu_Name_Control extends WP_Customize_Control {
1862
1863         /**
1864          * Type of control, used by JS.
1865          *
1866          * @since 4.3.0
1867          * @access public
1868          * @var string
1869          */
1870         public $type = 'nav_menu_name';
1871
1872         /**
1873          * No-op since we're using JS template.
1874          *
1875          * @since 4.3.0
1876          * @access protected
1877          */
1878         protected function render_content() {}
1879
1880         /**
1881          * Render the Underscore template for this control.
1882          *
1883          * @since 4.3.0
1884          * @access protected
1885          */
1886         protected function content_template() {
1887                 ?>
1888                 <label>
1889                         <# if ( data.label ) { #>
1890                                 <span class="customize-control-title screen-reader-text">{{ data.label }}</span>
1891                         <# } #>
1892                         <input type="text" class="menu-name-field live-update-section-title" />
1893                 </label>
1894                 <?php
1895         }
1896 }
1897
1898 /**
1899  * Customize control to represent the auto_add field for a given menu.
1900  *
1901  * @since 4.3.0
1902  *
1903  * @see WP_Customize_Control
1904  */
1905 class WP_Customize_Nav_Menu_Auto_Add_Control extends WP_Customize_Control {
1906
1907         /**
1908          * Type of control, used by JS.
1909          *
1910          * @since 4.3.0
1911          * @access public
1912          * @var string
1913          */
1914         public $type = 'nav_menu_auto_add';
1915
1916         /**
1917          * No-op since we're using JS template.
1918          *
1919          * @since 4.3.0
1920          * @access protected
1921          */
1922         protected function render_content() {}
1923
1924         /**
1925          * Render the Underscore template for this control.
1926          *
1927          * @since 4.3.0
1928          * @access protected
1929          */
1930         protected function content_template() {
1931                 ?>
1932                 <span class="customize-control-title"><?php _e( 'Menu options' ); ?></span>
1933                 <label>
1934                         <input type="checkbox" class="auto_add" />
1935                         <?php _e( 'Automatically add new top-level pages to this menu' ); ?>
1936                 </label>
1937                 <?php
1938         }
1939 }
1940
1941 /**
1942  * Customize control class for new menus.
1943  *
1944  * @since 4.3.0
1945  *
1946  * @see WP_Customize_Control
1947  */
1948 class WP_Customize_New_Menu_Control extends WP_Customize_Control {
1949
1950         /**
1951          * Control type.
1952          *
1953          * @since 4.3.0
1954          * @access public
1955          * @var string
1956          */
1957         public $type = 'new_menu';
1958
1959         /**
1960          * Render the control's content.
1961          *
1962          * @since 4.3.0
1963          * @access public
1964          */
1965         public function render_content() {
1966                 ?>
1967                 <button type="button" class="button button-primary" id="create-new-menu-submit"><?php _e( 'Create Menu' ); ?></button>
1968                 <span class="spinner"></span>
1969                 <?php
1970         }
1971 }