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