WordPress 3.4
[autoinstalls/wordpress.git] / wp-admin / custom-header.php
1 <?php
2 /**
3  * The custom header image script.
4  *
5  * @package WordPress
6  * @subpackage Administration
7  */
8
9 /**
10  * The custom header image class.
11  *
12  * @since 2.1.0
13  * @package WordPress
14  * @subpackage Administration
15  */
16 class Custom_Image_Header {
17
18         /**
19          * Callback for administration header.
20          *
21          * @var callback
22          * @since 2.1.0
23          * @access private
24          */
25         var $admin_header_callback;
26
27         /**
28          * Callback for header div.
29          *
30          * @var callback
31          * @since 3.0.0
32          * @access private
33          */
34         var $admin_image_div_callback;
35
36         /**
37          * Holds default headers.
38          *
39          * @var array
40          * @since 3.0.0
41          * @access private
42          */
43         var $default_headers = array();
44
45         /**
46          * Holds custom headers uploaded by the user
47          *
48          * @var array
49          * @since 3.2.0
50          * @access private
51          */
52         var $uploaded_headers = array();
53
54         /**
55          * Holds the page menu hook.
56          *
57          * @var string
58          * @since 3.0.0
59          * @access private
60          */
61         var $page = '';
62
63         /**
64          * Constructor - Register administration header callback.
65          *
66          * @since 2.1.0
67          * @param callback $admin_header_callback
68          * @param callback $admin_image_div_callback Optional custom image div output callback.
69          * @return Custom_Image_Header
70          */
71         function __construct($admin_header_callback, $admin_image_div_callback = '') {
72                 $this->admin_header_callback = $admin_header_callback;
73                 $this->admin_image_div_callback = $admin_image_div_callback;
74
75                 add_action( 'admin_menu', array( $this, 'init' ) );
76         }
77
78         /**
79          * Set up the hooks for the Custom Header admin page.
80          *
81          * @since 2.1.0
82          */
83         function init() {
84                 if ( ! current_user_can('edit_theme_options') )
85                         return;
86
87                 $this->page = $page = add_theme_page(__('Header'), __('Header'), 'edit_theme_options', 'custom-header', array(&$this, 'admin_page'));
88
89                 add_action("admin_print_scripts-$page", array(&$this, 'js_includes'));
90                 add_action("admin_print_styles-$page", array(&$this, 'css_includes'));
91                 add_action("admin_head-$page", array(&$this, 'help') );
92                 add_action("admin_head-$page", array(&$this, 'take_action'), 50);
93                 add_action("admin_head-$page", array(&$this, 'js'), 50);
94                 if ( $this->admin_header_callback )
95                         add_action("admin_head-$page", $this->admin_header_callback, 51);
96
97                 if ( isset( $_REQUEST['context'] ) && $_REQUEST['context'] == 'custom-header' ) {
98                         add_filter( 'attachment_fields_to_edit', array( $this, 'attachment_fields_to_edit' ), 10, 2 );
99                         add_filter( 'media_upload_tabs', array( $this, 'filter_upload_tabs' ) );
100                         add_filter( 'media_upload_mime_type_links', '__return_empty_array' );
101                 }
102         }
103
104         /**
105          * Adds contextual help.
106          *
107          * @since 3.0.0
108          */
109         function help() {
110                 get_current_screen()->add_help_tab( array(
111                         'id'      => 'overview',
112                         'title'   => __('Overview'),
113                         'content' =>
114                                 '<p>' . __( 'This screen is used to customize the header section of your theme.') . '</p>' .
115                                 '<p>' . __( 'You can choose from the theme&#8217;s default header images, or use one of your own. You can also customize how your Site Title and Tagline are displayed.') . '<p>'
116                 ) );
117
118                 get_current_screen()->add_help_tab( array(
119                         'id'      => 'set-header-image',
120                         'title'   => __('Header Image'),
121                         'content' =>
122                                 '<p>' . __( 'You can set a custom image header for your site. Simply upload the image and crop it, and the new header will go live immediately. Alternatively, you can use an image that has already been uploaded to your Media Library by clicking the &#8220;Choose Image&#8221; button.' ) . '</p>' .
123                                 '<p>' . __( 'Some themes come with additional header images bundled. If you see multiple images displayed, select the one you&#8217;d like and click the &#8220;Save Changes&#8221; button.' ) . '</p>' .
124                                 '<p>' . __( 'If your theme has more than one default header image, or you have uploaded more than one custom header image, you have the option of having WordPress display a randomly different image on each page of your site. Click the &#8220;Random&#8221; radio button next to the Uploaded Images or Default Images section to enable this feature.') . '</p>' .
125                                 '<p>' . __( 'If you don&#8217;t want a header image to be displayed on your site at all, click the &#8220;Remove Header Image&#8221; button at the bottom of the Header Image section of this page. If you want to re-enable the header image later, you just have to select one of the other image options and click &#8220;Save Changes&#8221;.') . '</p>'
126                 ) );
127
128                 get_current_screen()->add_help_tab( array(
129                         'id'      => 'set-header-text',
130                         'title'   => __('Header Text'),
131                         'content' =>
132                                 '<p>' . sprintf( __( 'For most themes, the header text is your Site Title and Tagline, as defined in the <a href="%1$s">General Settings</a> section.' ), admin_url( 'options-general.php' ) ) . '<p>' .
133                                 '<p>' . __( 'In the Header Text section of this page, you can choose whether to display this text or hide it. You can also choose a color for the text by typing in a legitimate HTML hex value (eg: &#8220;#ff0000&#8221; for red) or by clicking &#8220;Select a Color&#8221; and dialing in a color using the color picker.') . '</p>' .
134                                 '<p>' . __( 'Don&#8217;t forget to Save Changes when you&#8217;re done!') . '</p>'
135                 ) );
136
137                 get_current_screen()->set_help_sidebar(
138                         '<p><strong>' . __( 'For more information:' ) . '</strong></p>' .
139                         '<p>' . __( '<a href="http://codex.wordpress.org/Appearance_Header_Screen" target="_blank">Documentation on Custom Header</a>' ) . '</p>' .
140                         '<p>' . __( '<a href="http://wordpress.org/support/" target="_blank">Support Forums</a>' ) . '</p>'
141                 );
142         }
143
144         /**
145          * Get the current step.
146          *
147          * @since 2.6.0
148          *
149          * @return int Current step
150          */
151         function step() {
152                 if ( ! isset( $_GET['step'] ) )
153                         return 1;
154
155                 $step = (int) $_GET['step'];
156                 if ( $step < 1 || 3 < $step ||
157                         ( 2 == $step && ! wp_verify_nonce( $_REQUEST['_wpnonce-custom-header-upload'], 'custom-header-upload' ) ) ||
158                         ( 3 == $step && ! wp_verify_nonce( $_REQUEST['_wpnonce'], 'custom-header-crop-image' ) )
159                 )
160                         return 1;
161
162                 return $step;
163         }
164
165         /**
166          * Set up the enqueue for the JavaScript files.
167          *
168          * @since 2.1.0
169          */
170         function js_includes() {
171                 $step = $this->step();
172
173                 if ( ( 1 == $step || 3 == $step ) ) {
174                         add_thickbox();
175                         wp_enqueue_script( 'media-upload' );
176                         wp_enqueue_script( 'custom-header' );
177                         if ( current_theme_supports( 'custom-header', 'header-text' ) )
178                                 wp_enqueue_script('farbtastic');
179                 } elseif ( 2 == $step ) {
180                         wp_enqueue_script('imgareaselect');
181                 }
182         }
183
184         /**
185          * Set up the enqueue for the CSS files
186          *
187          * @since 2.7
188          */
189         function css_includes() {
190                 $step = $this->step();
191
192                 if ( ( 1 == $step || 3 == $step ) && current_theme_supports( 'custom-header', 'header-text' ) )
193                         wp_enqueue_style('farbtastic');
194                 elseif ( 2 == $step )
195                         wp_enqueue_style('imgareaselect');
196         }
197
198         /**
199          * Execute custom header modification.
200          *
201          * @since 2.6.0
202          */
203         function take_action() {
204                 if ( ! current_user_can('edit_theme_options') )
205                         return;
206
207                 if ( empty( $_POST ) )
208                         return;
209
210                 $this->updated = true;
211
212                 if ( isset( $_POST['resetheader'] ) ) {
213                         check_admin_referer( 'custom-header-options', '_wpnonce-custom-header-options' );
214                         $this->reset_header_image();
215                         return;
216                 }
217
218                 if ( isset( $_POST['resettext'] ) ) {
219                         check_admin_referer( 'custom-header-options', '_wpnonce-custom-header-options' );
220                         remove_theme_mod('header_textcolor');
221                         return;
222                 }
223
224                 if ( isset( $_POST['removeheader'] ) ) {
225                         check_admin_referer( 'custom-header-options', '_wpnonce-custom-header-options' );
226                         $this->remove_header_image();
227                         return;
228                 }
229
230                 if ( isset( $_POST['text-color'] ) && ! isset( $_POST['display-header-text'] ) ) {
231                         check_admin_referer( 'custom-header-options', '_wpnonce-custom-header-options' );
232                         set_theme_mod( 'header_textcolor', 'blank' );
233                 } elseif ( isset( $_POST['text-color'] ) ) {
234                         check_admin_referer( 'custom-header-options', '_wpnonce-custom-header-options' );
235                         $_POST['text-color'] = str_replace( '#', '', $_POST['text-color'] );
236                         $color = preg_replace('/[^0-9a-fA-F]/', '', $_POST['text-color']);
237                         if ( strlen($color) == 6 || strlen($color) == 3 )
238                                 set_theme_mod('header_textcolor', $color);
239                         elseif ( ! $color )
240                                 set_theme_mod( 'header_textcolor', 'blank' );
241                 }
242
243                 if ( isset( $_POST['default-header'] ) ) {
244                         check_admin_referer( 'custom-header-options', '_wpnonce-custom-header-options' );
245                         $this->set_header_image( $_POST['default-header'] );
246                         return;
247                 }
248         }
249
250         /**
251          * Process the default headers
252          *
253          * @since 3.0.0
254          */
255         function process_default_headers() {
256                 global $_wp_default_headers;
257
258                 if ( !empty($this->headers) )
259                         return;
260
261                 if ( !isset($_wp_default_headers) )
262                         return;
263
264                 $this->default_headers = $_wp_default_headers;
265                 $template_directory_uri = get_template_directory_uri();
266                 $stylesheet_directory_uri = get_stylesheet_directory_uri();
267                 foreach ( array_keys($this->default_headers) as $header ) {
268                         $this->default_headers[$header]['url'] =  sprintf( $this->default_headers[$header]['url'], $template_directory_uri, $stylesheet_directory_uri );
269                         $this->default_headers[$header]['thumbnail_url'] =  sprintf( $this->default_headers[$header]['thumbnail_url'], $template_directory_uri, $stylesheet_directory_uri );
270                 }
271
272         }
273
274         /**
275          * Display UI for selecting one of several default headers.
276          *
277          * Show the random image option if this theme has multiple header images.
278          * Random image option is on by default if no header has been set.
279          *
280          * @since 3.0.0
281          */
282         function show_header_selector( $type = 'default' ) {
283                 if ( 'default' == $type ) {
284                         $headers = $this->default_headers;
285                 } else {
286                         $headers = get_uploaded_header_images();
287                         $type = 'uploaded';
288                 }
289
290                 if ( 1 < count( $headers ) ) {
291                         echo '<div class="random-header">';
292                         echo '<label><input name="default-header" type="radio" value="random-' . $type . '-image"' . checked( is_random_header_image( $type ), true, false ) . ' />';
293                         echo __( '<strong>Random:</strong> Show a different image on each page.' );
294                         echo '</label>';
295                         echo '</div>';
296                 }
297
298                 echo '<div class="available-headers">';
299                 foreach ( $headers as $header_key => $header ) {
300                         $header_thumbnail = $header['thumbnail_url'];
301                         $header_url = $header['url'];
302                         $header_desc = empty( $header['description'] ) ? '' : $header['description'];
303                         echo '<div class="default-header">';
304                         echo '<label><input name="default-header" type="radio" value="' . esc_attr( $header_key ) . '" ' . checked( $header_url, get_theme_mod( 'header_image' ), false ) . ' />';
305                         $width = '';
306                         if ( !empty( $header['attachment_id'] ) )
307                                 $width = ' width="230"';
308                         echo '<img src="' . set_url_scheme( $header_thumbnail ) . '" alt="' . esc_attr( $header_desc ) .'" title="' . esc_attr( $header_desc ) . '"' . $width . ' /></label>';
309                         echo '</div>';
310                 }
311                 echo '<div class="clear"></div></div>';
312         }
313
314         /**
315          * Execute Javascript depending on step.
316          *
317          * @since 2.1.0
318          */
319         function js() {
320                 $step = $this->step();
321                 if ( ( 1 == $step || 3 == $step ) && current_theme_supports( 'custom-header', 'header-text' ) )
322                         $this->js_1();
323                 elseif ( 2 == $step )
324                         $this->js_2();
325         }
326
327         /**
328          * Display Javascript based on Step 1 and 3.
329          *
330          * @since 2.6.0
331          */
332         function js_1() { ?>
333 <script type="text/javascript">
334 /* <![CDATA[ */
335 var farbtastic;
336 (function($){
337         var default_color = '#<?php echo get_theme_support( 'custom-header', 'default-text-color' ); ?>',
338                 header_text_fields;
339
340         function pickColor(color) {
341                 $('#name').css('color', color);
342                 $('#desc').css('color', color);
343                 $('#text-color').val(color);
344                 farbtastic.setColor(color);
345         }
346
347         function toggle_text() {
348                 var checked = $('#display-header-text').prop('checked'),
349                         text_color;
350                 header_text_fields.toggle( checked );
351                 if ( ! checked )
352                         return;
353                 text_color = $('#text-color');
354                 if ( '' == text_color.val().replace('#', '') ) {
355                         text_color.val( default_color );
356                         pickColor( default_color );
357                 } else {
358                         pickColor( text_color.val() );
359                 }
360         }
361
362         $(document).ready(function() {
363                 header_text_fields = $('.displaying-header-text');
364                 $('#pickcolor').click(function(e) {
365                         e.preventDefault();
366                         $('#color-picker').show();
367                 });
368
369                 $('#display-header-text').click( toggle_text );
370
371                 $('#defaultcolor').click(function() {
372                         pickColor(default_color);
373                         $('#text-color').val(default_color);
374                 });
375
376                 $('#text-color').keyup(function() {
377                         var _hex = $('#text-color').val();
378                         var hex = _hex;
379                         if ( hex[0] != '#' )
380                                 hex = '#' + hex;
381                         hex = hex.replace(/[^#a-fA-F0-9]+/, '');
382                         if ( hex != _hex )
383                                 $('#text-color').val(hex);
384                         if ( hex.length == 4 || hex.length == 7 )
385                                 pickColor( hex );
386                 });
387
388                 $(document).mousedown(function(){
389                         $('#color-picker').each( function() {
390                                 var display = $(this).css('display');
391                                 if (display == 'block')
392                                         $(this).fadeOut(2);
393                         });
394                 });
395
396                 farbtastic = $.farbtastic('#color-picker', function(color) { pickColor(color); });
397                 <?php if ( display_header_text() ) { ?>
398                 pickColor('#<?php echo get_header_textcolor(); ?>');
399                 <?php } else { ?>
400                 toggle_text();
401                 <?php } ?>
402         });
403 })(jQuery);
404 /* ]]> */
405 </script>
406 <?php
407         }
408
409         /**
410          * Display Javascript based on Step 2.
411          *
412          * @since 2.6.0
413          */
414         function js_2() { ?>
415 <script type="text/javascript">
416 /* <![CDATA[ */
417         function onEndCrop( coords ) {
418                 jQuery( '#x1' ).val(coords.x);
419                 jQuery( '#y1' ).val(coords.y);
420                 jQuery( '#width' ).val(coords.w);
421                 jQuery( '#height' ).val(coords.h);
422         }
423
424         jQuery(document).ready(function() {
425                 var xinit = <?php echo absint( get_theme_support( 'custom-header', 'width' ) ); ?>;
426                 var yinit = <?php echo absint( get_theme_support( 'custom-header', 'height' ) ); ?>;
427                 var ratio = xinit / yinit;
428                 var ximg = jQuery('img#upload').width();
429                 var yimg = jQuery('img#upload').height();
430
431                 if ( yimg < yinit || ximg < xinit ) {
432                         if ( ximg / yimg > ratio ) {
433                                 yinit = yimg;
434                                 xinit = yinit * ratio;
435                         } else {
436                                 xinit = ximg;
437                                 yinit = xinit / ratio;
438                         }
439                 }
440
441                 jQuery('img#upload').imgAreaSelect({
442                         handles: true,
443                         keys: true,
444                         show: true,
445                         x1: 0,
446                         y1: 0,
447                         x2: xinit,
448                         y2: yinit,
449                         <?php
450                         if ( ! current_theme_supports( 'custom-header', 'flex-height' ) && ! current_theme_supports( 'custom-header', 'flex-width' ) ) {
451                         ?>
452                         aspectRatio: xinit + ':' + yinit,
453                         <?php
454                         }
455                         if ( ! current_theme_supports( 'custom-header', 'flex-height' ) ) {
456                         ?>
457                         maxHeight: <?php echo get_theme_support( 'custom-header', 'height' ); ?>,
458                         <?php
459                         }
460                         if ( ! current_theme_supports( 'custom-header', 'flex-width' ) ) {
461                         ?>
462                         maxWidth: <?php echo get_theme_support( 'custom-header', 'width' ); ?>,
463                         <?php
464                         }
465                         ?>
466                         onInit: function () {
467                                 jQuery('#width').val(xinit);
468                                 jQuery('#height').val(yinit);
469                         },
470                         onSelectChange: function(img, c) {
471                                 jQuery('#x1').val(c.x1);
472                                 jQuery('#y1').val(c.y1);
473                                 jQuery('#width').val(c.width);
474                                 jQuery('#height').val(c.height);
475                         }
476                 });
477         });
478 /* ]]> */
479 </script>
480 <?php
481         }
482
483         /**
484          * Display first step of custom header image page.
485          *
486          * @since 2.1.0
487          */
488         function step_1() {
489                 $this->process_default_headers();
490 ?>
491
492 <div class="wrap">
493 <?php screen_icon(); ?>
494 <h2><?php _e('Custom Header'); ?></h2>
495
496 <?php if ( ! empty( $this->updated ) ) { ?>
497 <div id="message" class="updated">
498 <p><?php printf( __( 'Header updated. <a href="%s">Visit your site</a> to see how it looks.' ), home_url( '/' ) ); ?></p>
499 </div>
500 <?php } ?>
501
502 <h3><?php _e( 'Header Image' ); ?></h3>
503
504 <table class="form-table">
505 <tbody>
506
507 <tr valign="top">
508 <th scope="row"><?php _e( 'Preview' ); ?></th>
509 <td>
510         <?php if ( $this->admin_image_div_callback ) {
511           call_user_func( $this->admin_image_div_callback );
512         } else {
513         ?>
514         <div id="headimg" style="background-image:url(<?php esc_url ( header_image() ) ?>);max-width:<?php echo get_custom_header()->width; ?>px;height:<?php echo get_custom_header()->height; ?>px;">
515                 <?php
516                 if ( display_header_text() )
517                         $style = ' style="color:#' . get_header_textcolor() . ';"';
518                 else
519                         $style = ' style="display:none;"';
520                 ?>
521                 <h1><a id="name" class="displaying-header-text" <?php echo $style; ?> onclick="return false;" href="<?php bloginfo('url'); ?>"><?php bloginfo( 'name' ); ?></a></h1>
522                 <div id="desc" class="displaying-header-text" <?php echo $style; ?>><?php bloginfo( 'description' ); ?></div>
523         </div>
524         <?php } ?>
525 </td>
526 </tr>
527 <?php if ( current_theme_supports( 'custom-header', 'uploads' ) ) : ?>
528 <tr valign="top">
529 <th scope="row"><?php _e( 'Select Image' ); ?></th>
530 <td>
531         <p><?php _e( 'You can upload a custom header image to be shown at the top of your site instead of the default one. On the next screen you will be able to crop the image.' ); ?><br />
532         <?php
533         if ( ! current_theme_supports( 'custom-header', 'flex-height' ) && ! current_theme_supports( 'custom-header', 'flex-width' ) ) {
534                 printf( __( 'Images of exactly <strong>%1$d &times; %2$d pixels</strong> will be used as-is.' ) . '<br />', get_theme_support( 'custom-header', 'width' ), get_theme_support( 'custom-header', 'height' ) );
535         } elseif ( current_theme_supports( 'custom-header', 'flex-height' ) ) {
536                 if ( ! current_theme_supports( 'custom-header', 'flex-width' ) )
537                         printf( __( 'Images should be at least <strong>%1$d pixels</strong> wide.' ) . ' ', get_theme_support( 'custom-header', 'width' ) );
538         } elseif ( current_theme_supports( 'custom-header', 'flex-width' ) ) {
539                 if ( ! current_theme_supports( 'custom-header', 'flex-height' ) )
540                         printf( __( 'Images should be at least <strong>%1$d pixels</strong> tall.' ) . ' ', get_theme_support( 'custom-header', 'height' ) );
541         }
542         if ( current_theme_supports( 'custom-header', 'flex-height' ) || current_theme_supports( 'custom-header', 'flex-width' ) ) {
543                 if ( current_theme_supports( 'custom-header', 'width' ) )
544                         printf( __( 'Suggested width is <strong>%1$d pixels</strong>.' ) . ' ', get_theme_support( 'custom-header', 'width' ) );
545                 if ( current_theme_supports( 'custom-header', 'height' ) )
546                         printf( __( 'Suggested height is <strong>%1$d pixels</strong>.' ) . ' ', get_theme_support( 'custom-header', 'height' ) );
547         }
548         ?></p>
549         <form enctype="multipart/form-data" id="upload-form" method="post" action="<?php echo esc_attr( add_query_arg( 'step', 2 ) ) ?>">
550         <p>
551                 <label for="upload"><?php _e( 'Choose an image from your computer:' ); ?></label><br />
552                 <input type="file" id="upload" name="import" />
553                 <input type="hidden" name="action" value="save" />
554                 <?php wp_nonce_field( 'custom-header-upload', '_wpnonce-custom-header-upload' ); ?>
555                 <?php submit_button( __( 'Upload' ), 'button', 'submit', false ); ?>
556         </p>
557         <?php
558                 $image_library_url = get_upload_iframe_src( 'image', null, 'library' );
559                 $image_library_url = remove_query_arg( 'TB_iframe', $image_library_url );
560                 $image_library_url = add_query_arg( array( 'context' => 'custom-header', 'TB_iframe' => 1 ), $image_library_url );
561         ?>
562         <p>
563                 <label for="choose-from-library-link"><?php _e( 'Or choose an image from your media library:' ); ?></label><br />
564                 <a id="choose-from-library-link" class="button thickbox" href="<?php echo esc_url( $image_library_url ); ?>"><?php _e( 'Choose Image' ); ?></a>
565         </p>
566         </form>
567 </td>
568 </tr>
569 <?php endif; ?>
570 </tbody>
571 </table>
572
573 <form method="post" action="<?php echo esc_attr( add_query_arg( 'step', 1 ) ) ?>">
574 <table class="form-table">
575 <tbody>
576         <?php if ( get_uploaded_header_images() ) : ?>
577 <tr valign="top">
578 <th scope="row"><?php _e( 'Uploaded Images' ); ?></th>
579 <td>
580         <p><?php _e( 'You can choose one of your previously uploaded headers, or show a random one.' ) ?></p>
581         <?php
582                 $this->show_header_selector( 'uploaded' );
583         ?>
584 </td>
585 </tr>
586         <?php endif;
587         if ( ! empty( $this->default_headers ) ) : ?>
588 <tr valign="top">
589 <th scope="row"><?php _e( 'Default Images' ); ?></th>
590 <td>
591 <?php if ( current_theme_supports( 'custom-header', 'uploads' ) ) : ?>
592         <p><?php _e( 'If you don&lsquo;t want to upload your own image, you can use one of these cool headers, or show a random one.' ) ?></p>
593 <?php else: ?>
594         <p><?php _e( 'You can use one of these cool headers or show a random one on each page.' ) ?></p>
595 <?php endif; ?>
596         <?php
597                 $this->show_header_selector( 'default' );
598         ?>
599 </td>
600 </tr>
601         <?php endif;
602         if ( get_header_image() ) : ?>
603 <tr valign="top">
604 <th scope="row"><?php _e( 'Remove Image' ); ?></th>
605 <td>
606         <p><?php _e( 'This will remove the header image. You will not be able to restore any customizations.' ) ?></p>
607         <?php submit_button( __( 'Remove Header Image' ), 'button', 'removeheader', false ); ?>
608 </td>
609 </tr>
610         <?php endif;
611
612         $default_image = get_theme_support( 'custom-header', 'default-image' );
613         if ( $default_image && get_header_image() != $default_image ) : ?>
614 <tr valign="top">
615 <th scope="row"><?php _e( 'Reset Image' ); ?></th>
616 <td>
617         <p><?php _e( 'This will restore the original header image. You will not be able to restore any customizations.' ) ?></p>
618         <?php submit_button( __( 'Restore Original Header Image' ), 'button', 'resetheader', false ); ?>
619 </td>
620 </tr>
621         <?php endif; ?>
622 </tbody>
623 </table>
624
625 <?php if ( current_theme_supports( 'custom-header', 'header-text' ) ) : ?>
626
627 <h3><?php _e( 'Header Text' ); ?></h3>
628
629 <table class="form-table">
630 <tbody>
631 <tr valign="top">
632 <th scope="row"><?php _e( 'Header Text' ); ?></th>
633 <td>
634         <p>
635         <label><input type="checkbox" name="display-header-text" id="display-header-text"<?php checked( display_header_text() ); ?> /> <?php _e( 'Show header text with your image.' ); ?></label>
636         </p>
637 </td>
638 </tr>
639
640 <tr valign="top" class="displaying-header-text">
641 <th scope="row"><?php _e( 'Text Color' ); ?></th>
642 <td>
643         <p>
644 <?php if ( display_header_text() ) : ?>
645                 <input type="text" name="text-color" id="text-color" value="#<?php echo esc_attr( get_header_textcolor() ); ?>" />
646 <?php else : ?>
647                 <input type="text" name="text-color" id="text-color" value="#<?php echo esc_attr( get_theme_support( 'custom-header', 'default-text-color' ) ); ?>" />
648 <?php endif; ?>
649                 <a href="#" class="hide-if-no-js" id="pickcolor"><?php _e( 'Select a Color' ); ?></a>
650         </p>
651         <div id="color-picker" style="z-index: 100; background:#eee; border:1px solid #ccc; position:absolute; display:none;"></div>
652 </td>
653 </tr>
654
655         <?php if ( current_theme_supports( 'custom-header', 'default-text-color' ) && get_theme_mod( 'header_textcolor' ) ) { ?>
656 <tr valign="top">
657 <th scope="row"><?php _e('Reset Text Color'); ?></th>
658 <td>
659         <p><?php _e( 'This will restore the original header text. You will not be able to restore any customizations.' ) ?></p>
660         <?php submit_button( __( 'Restore Original Header Text' ), 'button', 'resettext', false ); ?>
661 </td>
662 </tr>
663         <?php } ?>
664
665 </tbody>
666 </table>
667 <?php endif;
668
669 do_action( 'custom_header_options' );
670
671 wp_nonce_field( 'custom-header-options', '_wpnonce-custom-header-options' ); ?>
672
673 <?php submit_button( null, 'primary', 'save-header-options' ); ?>
674 </form>
675 </div>
676
677 <?php }
678
679         /**
680          * Display second step of custom header image page.
681          *
682          * @since 2.1.0
683          */
684         function step_2() {
685                 check_admin_referer('custom-header-upload', '_wpnonce-custom-header-upload');
686                 if ( ! current_theme_supports( 'custom-header', 'uploads' ) )
687                         wp_die( __( 'Cheatin&#8217; uh?' ) );
688
689                 if ( empty( $_POST ) && isset( $_GET['file'] ) ) {
690                         $attachment_id = absint( $_GET['file'] );
691                         $file = get_attached_file( $attachment_id, true );
692                         $url = wp_get_attachment_image_src( $attachment_id, 'full');
693                         $url = $url[0];
694                 } elseif ( isset( $_POST ) ) {
695                         extract($this->step_2_manage_upload());
696                 }
697
698                 if ( file_exists( $file ) ) {
699                         list( $width, $height, $type, $attr ) = getimagesize( $file );
700                 } else {
701                         $data = wp_get_attachment_metadata( $attachment_id );
702                         $height = $data[ 'height' ];
703                         $width = $data[ 'width' ];
704                         unset( $data );
705                 }
706
707                 $max_width = 0;
708                 // For flex, limit size of image displayed to 1500px unless theme says otherwise
709                 if ( current_theme_supports( 'custom-header', 'flex-width' ) )
710                         $max_width = 1500;
711
712                 if ( current_theme_supports( 'custom-header', 'max-width' ) )
713                         $max_width = max( $max_width, get_theme_support( 'custom-header', 'max-width' ) );
714                 $max_width = max( $max_width, get_theme_support( 'custom-header', 'width' ) );
715
716                 // If flexible height isn't supported and the image is the exact right size
717                 if ( ! current_theme_supports( 'custom-header', 'flex-height' ) && ! current_theme_supports( 'custom-header', 'flex-width' )
718                         && $width == get_theme_support( 'custom-header', 'width' ) && $height == get_theme_support( 'custom-header', 'height' ) )
719                 {
720                         // Add the meta-data
721                         if ( file_exists( $file ) )
722                                 wp_update_attachment_metadata( $attachment_id, wp_generate_attachment_metadata( $attachment_id, $file ) );
723
724                         $this->set_header_image( compact( 'url', 'attachment_id', 'width', 'height' ) );
725
726                         do_action('wp_create_file_in_uploads', $file, $attachment_id); // For replication
727                         return $this->finished();
728                 } elseif ( $width > $max_width ) {
729                         $oitar = $width / $max_width;
730                         $image = wp_crop_image($attachment_id, 0, 0, $width, $height, $max_width, $height / $oitar, false, str_replace(basename($file), 'midsize-'.basename($file), $file));
731                         if ( ! $image || is_wp_error( $image ) )
732                                 wp_die( __( 'Image could not be processed. Please go back and try again.' ), __( 'Image Processing Error' ) );
733
734                         $image = apply_filters('wp_create_file_in_uploads', $image, $attachment_id); // For replication
735
736                         $url = str_replace(basename($url), basename($image), $url);
737                         $width = $width / $oitar;
738                         $height = $height / $oitar;
739                 } else {
740                         $oitar = 1;
741                 }
742                 ?>
743
744 <div class="wrap">
745 <?php screen_icon(); ?>
746 <h2><?php _e( 'Crop Header Image' ); ?></h2>
747
748 <form method="post" action="<?php echo esc_attr(add_query_arg('step', 3)); ?>">
749         <p class="hide-if-no-js"><?php _e('Choose the part of the image you want to use as your header.'); ?></p>
750         <p class="hide-if-js"><strong><?php _e( 'You need Javascript to choose a part of the image.'); ?></strong></p>
751
752         <div id="crop_image" style="position: relative">
753                 <img src="<?php echo esc_url( $url ); ?>" id="upload" width="<?php echo $width; ?>" height="<?php echo $height; ?>" />
754         </div>
755
756         <input type="hidden" name="x1" id="x1" value="0"/>
757         <input type="hidden" name="y1" id="y1" value="0"/>
758         <input type="hidden" name="width" id="width" value="<?php echo esc_attr( $width ); ?>"/>
759         <input type="hidden" name="height" id="height" value="<?php echo esc_attr( $height ); ?>"/>
760         <input type="hidden" name="attachment_id" id="attachment_id" value="<?php echo esc_attr( $attachment_id ); ?>" />
761         <input type="hidden" name="oitar" id="oitar" value="<?php echo esc_attr( $oitar ); ?>" />
762         <?php if ( empty( $_POST ) && isset( $_GET['file'] ) ) { ?>
763         <input type="hidden" name="create-new-attachment" value="true" />
764         <?php } ?>
765         <?php wp_nonce_field( 'custom-header-crop-image' ) ?>
766
767         <p class="submit">
768         <?php submit_button( __( 'Crop and Publish' ), 'primary', 'submit', false ); ?>
769         <?php
770         if ( isset( $oitar ) && 1 == $oitar )
771                 submit_button( __( 'Skip Cropping, Publish Image as Is' ), 'secondary', 'skip-cropping', false );
772         ?>
773         </p>
774 </form>
775 </div>
776                 <?php
777         }
778
779
780         /**
781          * Upload the file to be cropped in the second step.
782          *
783          * @since 3.4.0
784          */
785         function step_2_manage_upload() {
786                 $overrides = array('test_form' => false);
787                 $file = wp_handle_upload($_FILES['import'], $overrides);
788
789                 if ( isset($file['error']) )
790                         wp_die( $file['error'],  __( 'Image Upload Error' ) );
791
792                 $url = $file['url'];
793                 $type = $file['type'];
794                 $file = $file['file'];
795                 $filename = basename($file);
796
797                 // Construct the object array
798                 $object = array(
799                         'post_title'     => $filename,
800                         'post_content'   => $url,
801                         'post_mime_type' => $type,
802                         'guid'           => $url,
803                         'context'        => 'custom-header'
804                 );
805
806                 // Save the data
807                 $attachment_id = wp_insert_attachment( $object, $file );
808                 return compact( 'attachment_id', 'file', 'filename', 'url', 'type' );
809         }
810
811         /**
812          * Display third step of custom header image page.
813          *
814          * @since 2.1.0
815          */
816         function step_3() {
817                 check_admin_referer( 'custom-header-crop-image' );
818
819                 if ( ! current_theme_supports( 'custom-header', 'uploads' ) )
820                         wp_die( __( 'Cheatin&#8217; uh?' ) );
821
822                 if ( $_POST['oitar'] > 1 ) {
823                         $_POST['x1'] = $_POST['x1'] * $_POST['oitar'];
824                         $_POST['y1'] = $_POST['y1'] * $_POST['oitar'];
825                         $_POST['width'] = $_POST['width'] * $_POST['oitar'];
826                         $_POST['height'] = $_POST['height'] * $_POST['oitar'];
827                 }
828
829                 $attachment_id = absint( $_POST['attachment_id'] );
830                 $original = get_attached_file($attachment_id);
831
832
833                 $max_width = 0;
834                 // For flex, limit size of image displayed to 1500px unless theme says otherwise
835                 if ( current_theme_supports( 'custom-header', 'flex-width' ) )
836                         $max_width = 1500;
837
838                 if ( current_theme_supports( 'custom-header', 'max-width' ) )
839                         $max_width = max( $max_width, get_theme_support( 'custom-header', 'max-width' ) );
840                 $max_width = max( $max_width, get_theme_support( 'custom-header', 'width' ) );
841
842                 if ( ( current_theme_supports( 'custom-header', 'flex-height' ) && ! current_theme_supports( 'custom-header', 'flex-width' ) ) || $_POST['width'] > $max_width )
843                         $dst_height = absint( $_POST['height'] * ( $max_width / $_POST['width'] ) );
844                 elseif ( current_theme_supports( 'custom-header', 'flex-height' ) && current_theme_supports( 'custom-header', 'flex-width' ) )
845                         $dst_height = absint( $_POST['height'] );
846                 else
847                         $dst_height = get_theme_support( 'custom-header', 'height' );
848
849                 if ( ( current_theme_supports( 'custom-header', 'flex-width' ) && ! current_theme_supports( 'custom-header', 'flex-height' ) ) || $_POST['width'] > $max_width )
850                         $dst_width = absint( $_POST['width'] * ( $max_width / $_POST['width'] ) );
851                 elseif ( current_theme_supports( 'custom-header', 'flex-width' ) && current_theme_supports( 'custom-header', 'flex-height' ) )
852                         $dst_width = absint( $_POST['width'] );
853                 else
854                         $dst_width = get_theme_support( 'custom-header', 'width' );
855
856                 if ( empty( $_POST['skip-cropping'] ) )
857                         $cropped = wp_crop_image( $attachment_id, (int) $_POST['x1'], (int) $_POST['y1'], (int) $_POST['width'], (int) $_POST['height'], $dst_width, $dst_height );
858                 elseif ( ! empty( $_POST['create-new-attachment'] ) )
859                         $cropped = _copy_image_file( $attachment_id );
860                 else
861                         $cropped = get_attached_file( $attachment_id );
862
863                 if ( ! $cropped || is_wp_error( $cropped ) )
864                         wp_die( __( 'Image could not be processed. Please go back and try again.' ), __( 'Image Processing Error' ) );
865
866                 $cropped = apply_filters('wp_create_file_in_uploads', $cropped, $attachment_id); // For replication
867
868                 $parent = get_post($attachment_id);
869                 $parent_url = $parent->guid;
870                 $url = str_replace( basename( $parent_url ), basename( $cropped ), $parent_url );
871
872                 $size = @getimagesize( $cropped );
873                 $image_type = ( $size ) ? $size['mime'] : 'image/jpeg';
874
875                 // Construct the object array
876                 $object = array(
877                         'ID' => $attachment_id,
878                         'post_title' => basename($cropped),
879                         'post_content' => $url,
880                         'post_mime_type' => $image_type,
881                         'guid' => $url,
882                         'context' => 'custom-header'
883                 );
884                 if ( ! empty( $_POST['create-new-attachment'] ) )
885                         unset( $object['ID'] );
886
887                 // Update the attachment
888                 $attachment_id = wp_insert_attachment( $object, $cropped );
889                 wp_update_attachment_metadata( $attachment_id, wp_generate_attachment_metadata( $attachment_id, $cropped ) );
890
891                 $width = $dst_width;
892                 $height = $dst_height;
893                 $this->set_header_image( compact( 'url', 'attachment_id', 'width', 'height' ) );
894
895                 // cleanup
896                 $medium = str_replace( basename( $original ), 'midsize-' . basename( $original ), $original );
897                 if ( file_exists( $medium ) )
898                         @unlink( apply_filters( 'wp_delete_file', $medium ) );
899                 if ( empty( $_POST['create-new-attachment'] ) && empty( $_POST['skip-cropping'] ) )
900                         @unlink( apply_filters( 'wp_delete_file', $original ) );
901
902                 return $this->finished();
903         }
904
905         /**
906          * Display last step of custom header image page.
907          *
908          * @since 2.1.0
909          */
910         function finished() {
911                 $this->updated = true;
912                 $this->step_1();
913         }
914
915         /**
916          * Display the page based on the current step.
917          *
918          * @since 2.1.0
919          */
920         function admin_page() {
921                 if ( ! current_user_can('edit_theme_options') )
922                         wp_die(__('You do not have permission to customize headers.'));
923                 $step = $this->step();
924                 if ( 2 == $step )
925                         $this->step_2();
926                 elseif ( 3 == $step )
927                         $this->step_3();
928                 else
929                         $this->step_1();
930         }
931
932         /**
933          * Replace default attachment actions with "Set as header" link.
934          *
935          * @since 3.4.0
936          */
937         function attachment_fields_to_edit( $form_fields, $post ) {
938                 $form_fields = array();
939                 $href = esc_url(add_query_arg(array(
940                         'page' => 'custom-header',
941                         'step' => 2,
942                         '_wpnonce-custom-header-upload' => wp_create_nonce('custom-header-upload'),
943                         'file' => $post->ID
944                 ), admin_url('themes.php')));
945
946                 $form_fields['buttons'] = array( 'tr' => '<tr class="submit"><td></td><td><a data-location="' . $href . '" class="wp-set-header">' . __( 'Set as header' ) . '</a></td></tr>' );
947                 $form_fields['context'] = array( 'input' => 'hidden', 'value' => 'custom-header' );
948
949                 return $form_fields;
950         }
951
952         /**
953          * Leave only "Media Library" tab in the uploader window.
954          *
955          * @since 3.4.0
956          */
957         function filter_upload_tabs() {
958                 return array( 'library' => __('Media Library') );
959         }
960
961         /**
962          * Choose a header image, selected from existing uploaded and default headers,
963          * or provide an array of uploaded header data (either new, or from media library).
964          *
965          * @param mixed $choice Which header image to select. Allows for values of 'random-default-image',
966          *      for randomly cycling among the default images; 'random-uploaded-image', for randomly cycling
967          *      among the uploaded images; the key of a default image registered for that theme; and
968          *      the key of an image uploaded for that theme (the basename of the URL).
969          *  Or an array of arguments: attachment_id, url, width, height. All are required.
970          *
971          * @since 3.4.0
972          */
973         final public function set_header_image( $choice ) {
974                 if ( is_array( $choice ) || is_object( $choice ) ) {
975                         $choice = (array) $choice;
976                         if ( ! isset( $choice['attachment_id'] ) || ! isset( $choice['url'] ) )
977                                 return;
978
979                         $choice['url'] = esc_url_raw( $choice['url'] );
980
981                         $header_image_data = (object) array(
982                                 'attachment_id' => $choice['attachment_id'],
983                                 'url'           => $choice['url'],
984                                 'thumbnail_url' => $choice['url'],
985                                 'height'        => $choice['height'],
986                                 'width'         => $choice['width'],
987                         );
988
989                         update_post_meta( $choice['attachment_id'], '_wp_attachment_is_custom_header', get_stylesheet() );
990                         set_theme_mod( 'header_image', $choice['url'] );
991                         set_theme_mod( 'header_image_data', $header_image_data );
992                         return;
993                 }
994
995                 if ( in_array( $choice, array( 'remove-header', 'random-default-image', 'random-uploaded-image' ) ) ) {
996                         set_theme_mod( 'header_image', $choice );
997                         remove_theme_mod( 'header_image_data' );
998                         return;
999                 }
1000
1001                 $uploaded = get_uploaded_header_images();
1002                 if ( $uploaded && isset( $uploaded[ $choice ] ) ) {
1003                         $header_image_data = $uploaded[ $choice ];
1004
1005                 } else {
1006                         $this->process_default_headers();
1007                         if ( isset( $this->default_headers[ $choice ] ) )
1008                                 $header_image_data = $this->default_headers[ $choice ];
1009                         else
1010                                 return;
1011                 }
1012
1013                 set_theme_mod( 'header_image', esc_url_raw( $header_image_data['url'] ) );
1014                 set_theme_mod( 'header_image_data', $header_image_data );
1015         }
1016
1017         /**
1018          * Remove a header image.
1019          *
1020          * @since 3.4.0
1021          */
1022         final public function remove_header_image() {
1023                 return $this->set_header_image( 'remove-header' );
1024         }
1025
1026         /**
1027          * Reset a header image to the default image for the theme.
1028          *
1029          * This method does not do anything if the theme does not have a default header image.
1030          *
1031          * @since 3.4.0
1032          */
1033         final public function reset_header_image() {
1034                 $this->process_default_headers();
1035                 $default = get_theme_support( 'custom-header', 'default-image' );
1036
1037                 if ( ! $default )
1038                         return $this->remove_header_image();
1039
1040                 $default = sprintf( $default, get_template_directory_uri(), get_stylesheet_directory_uri() );
1041
1042                 foreach ( $this->default_headers as $header => $details ) {
1043                         if ( $details['url'] == $default ) {
1044                                 $default_data = $details;
1045                                 break;
1046                         }
1047                 }
1048
1049                 set_theme_mod( 'header_image', $default );
1050                 set_theme_mod( 'header_image_data', (object) $default_data );
1051         }
1052 }