WordPress 3.8
[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 <h2><?php _e('Custom Header'); ?></h2>
454
455 <?php if ( ! empty( $this->updated ) ) { ?>
456 <div id="message" class="updated">
457 <p><?php printf( __( 'Header updated. <a href="%s">Visit your site</a> to see how it looks.' ), home_url( '/' ) ); ?></p>
458 </div>
459 <?php } ?>
460
461 <h3><?php _e( 'Header Image' ); ?></h3>
462
463 <table class="form-table">
464 <tbody>
465
466 <?php if ( get_custom_header() || display_header_text() ) : ?>
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 endif; ?>
494
495 <?php if ( current_theme_supports( 'custom-header', 'uploads' ) ) : ?>
496 <tr valign="top">
497 <th scope="row"><?php _e( 'Select Image' ); ?></th>
498 <td>
499         <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 />
500         <?php
501         if ( ! current_theme_supports( 'custom-header', 'flex-height' ) && ! current_theme_supports( 'custom-header', 'flex-width' ) ) {
502                 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' ) );
503         } elseif ( current_theme_supports( 'custom-header', 'flex-height' ) ) {
504                 if ( ! current_theme_supports( 'custom-header', 'flex-width' ) )
505                         printf( __( 'Images should be at least <strong>%1$d pixels</strong> wide.' ) . ' ', get_theme_support( 'custom-header', 'width' ) );
506         } elseif ( current_theme_supports( 'custom-header', 'flex-width' ) ) {
507                 if ( ! current_theme_supports( 'custom-header', 'flex-height' ) )
508                         printf( __( 'Images should be at least <strong>%1$d pixels</strong> tall.' ) . ' ', get_theme_support( 'custom-header', 'height' ) );
509         }
510         if ( current_theme_supports( 'custom-header', 'flex-height' ) || current_theme_supports( 'custom-header', 'flex-width' ) ) {
511                 if ( current_theme_supports( 'custom-header', 'width' ) )
512                         printf( __( 'Suggested width is <strong>%1$d pixels</strong>.' ) . ' ', get_theme_support( 'custom-header', 'width' ) );
513                 if ( current_theme_supports( 'custom-header', 'height' ) )
514                         printf( __( 'Suggested height is <strong>%1$d pixels</strong>.' ) . ' ', get_theme_support( 'custom-header', 'height' ) );
515         }
516         ?></p>
517         <form enctype="multipart/form-data" id="upload-form" class="wp-upload-form" method="post" action="<?php echo esc_url( add_query_arg( 'step', 2 ) ) ?>">
518         <p>
519                 <label for="upload"><?php _e( 'Choose an image from your computer:' ); ?></label><br />
520                 <input type="file" id="upload" name="import" />
521                 <input type="hidden" name="action" value="save" />
522                 <?php wp_nonce_field( 'custom-header-upload', '_wpnonce-custom-header-upload' ); ?>
523                 <?php submit_button( __( 'Upload' ), 'button', 'submit', false ); ?>
524         </p>
525         <?php
526                 $modal_update_href = esc_url( add_query_arg( array(
527                         'page' => 'custom-header',
528                         'step' => 2,
529                         '_wpnonce-custom-header-upload' => wp_create_nonce('custom-header-upload'),
530                 ), admin_url('themes.php') ) );
531         ?>
532         <p>
533                 <label for="choose-from-library-link"><?php _e( 'Or choose an image from your media library:' ); ?></label><br />
534                 <a id="choose-from-library-link" class="button"
535                         data-update-link="<?php echo esc_attr( $modal_update_href ); ?>"
536                         data-choose="<?php esc_attr_e( 'Choose a Custom Header' ); ?>"
537                         data-update="<?php esc_attr_e( 'Set as header' ); ?>"><?php _e( 'Choose Image' ); ?></a>
538         </p>
539         </form>
540 </td>
541 </tr>
542 <?php endif; ?>
543 </tbody>
544 </table>
545
546 <form method="post" action="<?php echo esc_url( add_query_arg( 'step', 1 ) ) ?>">
547 <table class="form-table">
548 <tbody>
549         <?php if ( get_uploaded_header_images() ) : ?>
550 <tr valign="top">
551 <th scope="row"><?php _e( 'Uploaded Images' ); ?></th>
552 <td>
553         <p><?php _e( 'You can choose one of your previously uploaded headers, or show a random one.' ) ?></p>
554         <?php
555                 $this->show_header_selector( 'uploaded' );
556         ?>
557 </td>
558 </tr>
559         <?php endif;
560         if ( ! empty( $this->default_headers ) ) : ?>
561 <tr valign="top">
562 <th scope="row"><?php _e( 'Default Images' ); ?></th>
563 <td>
564 <?php if ( current_theme_supports( 'custom-header', 'uploads' ) ) : ?>
565         <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>
566 <?php else: ?>
567         <p><?php _e( 'You can use one of these cool headers or show a random one on each page.' ) ?></p>
568 <?php endif; ?>
569         <?php
570                 $this->show_header_selector( 'default' );
571         ?>
572 </td>
573 </tr>
574         <?php endif;
575         if ( get_header_image() ) : ?>
576 <tr valign="top">
577 <th scope="row"><?php _e( 'Remove Image' ); ?></th>
578 <td>
579         <p><?php _e( 'This will remove the header image. You will not be able to restore any customizations.' ) ?></p>
580         <?php submit_button( __( 'Remove Header Image' ), 'button', 'removeheader', false ); ?>
581 </td>
582 </tr>
583         <?php endif;
584
585         $default_image = get_theme_support( 'custom-header', 'default-image' );
586         if ( $default_image && get_header_image() != $default_image ) : ?>
587 <tr valign="top">
588 <th scope="row"><?php _e( 'Reset Image' ); ?></th>
589 <td>
590         <p><?php _e( 'This will restore the original header image. You will not be able to restore any customizations.' ) ?></p>
591         <?php submit_button( __( 'Restore Original Header Image' ), 'button', 'resetheader', false ); ?>
592 </td>
593 </tr>
594         <?php endif; ?>
595 </tbody>
596 </table>
597
598 <?php if ( current_theme_supports( 'custom-header', 'header-text' ) ) : ?>
599
600 <h3><?php _e( 'Header Text' ); ?></h3>
601
602 <table class="form-table">
603 <tbody>
604 <tr valign="top">
605 <th scope="row"><?php _e( 'Header Text' ); ?></th>
606 <td>
607         <p>
608         <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>
609         </p>
610 </td>
611 </tr>
612
613 <tr valign="top" class="displaying-header-text">
614 <th scope="row"><?php _e( 'Text Color' ); ?></th>
615 <td>
616         <p>
617 <?php
618 $header_textcolor = display_header_text() ? get_header_textcolor() : get_theme_support( 'custom-header', 'default-text-color' );
619 $default_color = '';
620 if ( current_theme_supports( 'custom-header', 'default-text-color' ) ) {
621         $default_color = '#' . get_theme_support( 'custom-header', 'default-text-color' );
622         $default_color_attr = ' data-default-color="' . esc_attr( $default_color ) . '"';
623         echo '<input type="text" name="text-color" id="text-color" value="#' . esc_attr( $header_textcolor ) . '"' . $default_color_attr . ' />';
624         if ( $default_color )
625                 echo ' <span class="description hide-if-js">' . sprintf( _x( 'Default: %s', 'color' ), $default_color ) . '</span>';
626 }
627 ?>
628         </p>
629 </td>
630 </tr>
631 </tbody>
632 </table>
633 <?php endif;
634
635 /**
636  * Fires just before the submit button in the custom header options form.
637  *
638  * @since 3.1.0
639  */
640 do_action( 'custom_header_options' );
641
642 wp_nonce_field( 'custom-header-options', '_wpnonce-custom-header-options' ); ?>
643
644 <?php submit_button( null, 'primary', 'save-header-options' ); ?>
645 </form>
646 </div>
647
648 <?php }
649
650         /**
651          * Display second step of custom header image page.
652          *
653          * @since 2.1.0
654          */
655         function step_2() {
656                 check_admin_referer('custom-header-upload', '_wpnonce-custom-header-upload');
657                 if ( ! current_theme_supports( 'custom-header', 'uploads' ) )
658                         wp_die( __( 'Cheatin&#8217; uh?' ) );
659
660                 if ( empty( $_POST ) && isset( $_GET['file'] ) ) {
661                         $attachment_id = absint( $_GET['file'] );
662                         $file = get_attached_file( $attachment_id, true );
663                         $url = wp_get_attachment_image_src( $attachment_id, 'full');
664                         $url = $url[0];
665                 } elseif ( isset( $_POST ) ) {
666                         extract($this->step_2_manage_upload());
667                 }
668
669                 if ( file_exists( $file ) ) {
670                         list( $width, $height, $type, $attr ) = getimagesize( $file );
671                 } else {
672                         $data = wp_get_attachment_metadata( $attachment_id );
673                         $height = isset( $data[ 'height' ] ) ? $data[ 'height' ] : 0;
674                         $width = isset( $data[ 'width' ] ) ? $data[ 'width' ] : 0;
675                         unset( $data );
676                 }
677
678                 $max_width = 0;
679                 // For flex, limit size of image displayed to 1500px unless theme says otherwise
680                 if ( current_theme_supports( 'custom-header', 'flex-width' ) )
681                         $max_width = 1500;
682
683                 if ( current_theme_supports( 'custom-header', 'max-width' ) )
684                         $max_width = max( $max_width, get_theme_support( 'custom-header', 'max-width' ) );
685                 $max_width = max( $max_width, get_theme_support( 'custom-header', 'width' ) );
686
687                 // If flexible height isn't supported and the image is the exact right size
688                 if ( ! current_theme_supports( 'custom-header', 'flex-height' ) && ! current_theme_supports( 'custom-header', 'flex-width' )
689                         && $width == get_theme_support( 'custom-header', 'width' ) && $height == get_theme_support( 'custom-header', 'height' ) )
690                 {
691                         // Add the meta-data
692                         if ( file_exists( $file ) )
693                                 wp_update_attachment_metadata( $attachment_id, wp_generate_attachment_metadata( $attachment_id, $file ) );
694
695                         $this->set_header_image( compact( 'url', 'attachment_id', 'width', 'height' ) );
696
697                         /**
698                          * Fires after the header image is set or an error is returned.
699                          *
700                          * @since 2.1.0
701                          *
702                          * @param string $file          Path to the file.
703                          * @param int    $attachment_id Attachment ID.
704                          */
705                         do_action( 'wp_create_file_in_uploads', $file, $attachment_id ); // For replication
706
707                         return $this->finished();
708                 } elseif ( $width > $max_width ) {
709                         $oitar = $width / $max_width;
710                         $image = wp_crop_image($attachment_id, 0, 0, $width, $height, $max_width, $height / $oitar, false, str_replace(basename($file), 'midsize-'.basename($file), $file));
711                         if ( ! $image || is_wp_error( $image ) )
712                                 wp_die( __( 'Image could not be processed. Please go back and try again.' ), __( 'Image Processing Error' ) );
713
714                         /** This filter is documented in wp-admin/custom-header.php */
715                         $image = apply_filters( 'wp_create_file_in_uploads', $image, $attachment_id ); // For replication
716
717                         $url = str_replace(basename($url), basename($image), $url);
718                         $width = $width / $oitar;
719                         $height = $height / $oitar;
720                 } else {
721                         $oitar = 1;
722                 }
723                 ?>
724
725 <div class="wrap">
726 <h2><?php _e( 'Crop Header Image' ); ?></h2>
727
728 <form method="post" action="<?php echo esc_url(add_query_arg('step', 3)); ?>">
729         <p class="hide-if-no-js"><?php _e('Choose the part of the image you want to use as your header.'); ?></p>
730         <p class="hide-if-js"><strong><?php _e( 'You need Javascript to choose a part of the image.'); ?></strong></p>
731
732         <div id="crop_image" style="position: relative">
733                 <img src="<?php echo esc_url( $url ); ?>" id="upload" width="<?php echo $width; ?>" height="<?php echo $height; ?>" />
734         </div>
735
736         <input type="hidden" name="x1" id="x1" value="0"/>
737         <input type="hidden" name="y1" id="y1" value="0"/>
738         <input type="hidden" name="width" id="width" value="<?php echo esc_attr( $width ); ?>"/>
739         <input type="hidden" name="height" id="height" value="<?php echo esc_attr( $height ); ?>"/>
740         <input type="hidden" name="attachment_id" id="attachment_id" value="<?php echo esc_attr( $attachment_id ); ?>" />
741         <input type="hidden" name="oitar" id="oitar" value="<?php echo esc_attr( $oitar ); ?>" />
742         <?php if ( empty( $_POST ) && isset( $_GET['file'] ) ) { ?>
743         <input type="hidden" name="create-new-attachment" value="true" />
744         <?php } ?>
745         <?php wp_nonce_field( 'custom-header-crop-image' ) ?>
746
747         <p class="submit">
748         <?php submit_button( __( 'Crop and Publish' ), 'primary', 'submit', false ); ?>
749         <?php
750         if ( isset( $oitar ) && 1 == $oitar && ( current_theme_supports( 'custom-header', 'flex-height' ) || current_theme_supports( 'custom-header', 'flex-width' ) ) )
751                 submit_button( __( 'Skip Cropping, Publish Image as Is' ), 'secondary', 'skip-cropping', false );
752         ?>
753         </p>
754 </form>
755 </div>
756                 <?php
757         }
758
759
760         /**
761          * Upload the file to be cropped in the second step.
762          *
763          * @since 3.4.0
764          */
765         function step_2_manage_upload() {
766                 $overrides = array('test_form' => false);
767
768                 $uploaded_file = $_FILES['import'];
769                 $wp_filetype = wp_check_filetype_and_ext( $uploaded_file['tmp_name'], $uploaded_file['name'], false );
770                 if ( ! wp_match_mime_types( 'image', $wp_filetype['type'] ) )
771                         wp_die( __( 'The uploaded file is not a valid image. Please try again.' ) );
772
773                 $file = wp_handle_upload($uploaded_file, $overrides);
774
775                 if ( isset($file['error']) )
776                         wp_die( $file['error'],  __( 'Image Upload Error' ) );
777
778                 $url = $file['url'];
779                 $type = $file['type'];
780                 $file = $file['file'];
781                 $filename = basename($file);
782
783                 // Construct the object array
784                 $object = array(
785                         'post_title'     => $filename,
786                         'post_content'   => $url,
787                         'post_mime_type' => $type,
788                         'guid'           => $url,
789                         'context'        => 'custom-header'
790                 );
791
792                 // Save the data
793                 $attachment_id = wp_insert_attachment( $object, $file );
794                 return compact( 'attachment_id', 'file', 'filename', 'url', 'type' );
795         }
796
797         /**
798          * Display third step of custom header image page.
799          *
800          * @since 2.1.0
801          */
802         function step_3() {
803                 check_admin_referer( 'custom-header-crop-image' );
804
805                 if ( ! current_theme_supports( 'custom-header', 'uploads' ) )
806                         wp_die( __( 'Cheatin&#8217; uh?' ) );
807
808                 if ( ! empty( $_POST['skip-cropping'] ) && ! ( current_theme_supports( 'custom-header', 'flex-height' ) || current_theme_supports( 'custom-header', 'flex-width' ) ) )
809                         wp_die( __( 'Cheatin&#8217; uh?' ) );
810
811                 if ( $_POST['oitar'] > 1 ) {
812                         $_POST['x1'] = $_POST['x1'] * $_POST['oitar'];
813                         $_POST['y1'] = $_POST['y1'] * $_POST['oitar'];
814                         $_POST['width'] = $_POST['width'] * $_POST['oitar'];
815                         $_POST['height'] = $_POST['height'] * $_POST['oitar'];
816                 }
817
818                 $attachment_id = absint( $_POST['attachment_id'] );
819                 $original = get_attached_file($attachment_id);
820
821
822                 $max_width = 0;
823                 // For flex, limit size of image displayed to 1500px unless theme says otherwise
824                 if ( current_theme_supports( 'custom-header', 'flex-width' ) )
825                         $max_width = 1500;
826
827                 if ( current_theme_supports( 'custom-header', 'max-width' ) )
828                         $max_width = max( $max_width, get_theme_support( 'custom-header', 'max-width' ) );
829                 $max_width = max( $max_width, get_theme_support( 'custom-header', 'width' ) );
830
831                 if ( ( current_theme_supports( 'custom-header', 'flex-height' ) && ! current_theme_supports( 'custom-header', 'flex-width' ) ) || $_POST['width'] > $max_width )
832                         $dst_height = absint( $_POST['height'] * ( $max_width / $_POST['width'] ) );
833                 elseif ( current_theme_supports( 'custom-header', 'flex-height' ) && current_theme_supports( 'custom-header', 'flex-width' ) )
834                         $dst_height = absint( $_POST['height'] );
835                 else
836                         $dst_height = get_theme_support( 'custom-header', 'height' );
837
838                 if ( ( current_theme_supports( 'custom-header', 'flex-width' ) && ! current_theme_supports( 'custom-header', 'flex-height' ) ) || $_POST['width'] > $max_width )
839                         $dst_width = absint( $_POST['width'] * ( $max_width / $_POST['width'] ) );
840                 elseif ( current_theme_supports( 'custom-header', 'flex-width' ) && current_theme_supports( 'custom-header', 'flex-height' ) )
841                         $dst_width = absint( $_POST['width'] );
842                 else
843                         $dst_width = get_theme_support( 'custom-header', 'width' );
844
845                 if ( empty( $_POST['skip-cropping'] ) )
846                         $cropped = wp_crop_image( $attachment_id, (int) $_POST['x1'], (int) $_POST['y1'], (int) $_POST['width'], (int) $_POST['height'], $dst_width, $dst_height );
847                 elseif ( ! empty( $_POST['create-new-attachment'] ) )
848                         $cropped = _copy_image_file( $attachment_id );
849                 else
850                         $cropped = get_attached_file( $attachment_id );
851
852                 if ( ! $cropped || is_wp_error( $cropped ) )
853                         wp_die( __( 'Image could not be processed. Please go back and try again.' ), __( 'Image Processing Error' ) );
854
855                 /** This filter is documented in wp-admin/custom-header.php */
856                 $cropped = apply_filters( 'wp_create_file_in_uploads', $cropped, $attachment_id ); // For replication
857
858                 $parent = get_post($attachment_id);
859                 $parent_url = $parent->guid;
860                 $url = str_replace( basename( $parent_url ), basename( $cropped ), $parent_url );
861
862                 $size = @getimagesize( $cropped );
863                 $image_type = ( $size ) ? $size['mime'] : 'image/jpeg';
864
865                 // Construct the object array
866                 $object = array(
867                         'ID' => $attachment_id,
868                         'post_title' => basename($cropped),
869                         'post_content' => $url,
870                         'post_mime_type' => $image_type,
871                         'guid' => $url,
872                         'context' => 'custom-header'
873                 );
874                 if ( ! empty( $_POST['create-new-attachment'] ) )
875                         unset( $object['ID'] );
876
877                 // Update the attachment
878                 $attachment_id = wp_insert_attachment( $object, $cropped );
879                 wp_update_attachment_metadata( $attachment_id, wp_generate_attachment_metadata( $attachment_id, $cropped ) );
880
881                 $width = $dst_width;
882                 $height = $dst_height;
883                 $this->set_header_image( compact( 'url', 'attachment_id', 'width', 'height' ) );
884
885                 // cleanup
886                 $medium = str_replace( basename( $original ), 'midsize-' . basename( $original ), $original );
887                 if ( file_exists( $medium ) ) {
888                         /**
889                          * Filter the path of the file to delete.
890                          *
891                          * @since 2.1.0
892                          *
893                          * @param string $medium Path to the file to delete.
894                          */
895                         @unlink( apply_filters( 'wp_delete_file', $medium ) );
896                 }
897
898                 if ( empty( $_POST['create-new-attachment'] ) && empty( $_POST['skip-cropping'] ) ) {
899                         /** This filter is documented in wp-admin/custom-header.php */
900                         @unlink( apply_filters( 'wp_delete_file', $original ) );
901                 }
902
903                 return $this->finished();
904         }
905
906         /**
907          * Display last step of custom header image page.
908          *
909          * @since 2.1.0
910          */
911         function finished() {
912                 $this->updated = true;
913                 $this->step_1();
914         }
915
916         /**
917          * Display the page based on the current step.
918          *
919          * @since 2.1.0
920          */
921         function admin_page() {
922                 if ( ! current_user_can('edit_theme_options') )
923                         wp_die(__('You do not have permission to customize headers.'));
924                 $step = $this->step();
925                 if ( 2 == $step )
926                         $this->step_2();
927                 elseif ( 3 == $step )
928                         $this->step_3();
929                 else
930                         $this->step_1();
931         }
932
933         /**
934          * Unused since 3.5.0.
935          *
936          * @since 3.4.0
937          */
938         function attachment_fields_to_edit( $form_fields ) {
939                 return $form_fields;
940         }
941
942         /**
943          * Unused since 3.5.0.
944          *
945          * @since 3.4.0
946          */
947         function filter_upload_tabs( $tabs ) {
948                 return $tabs;
949         }
950
951         /**
952          * Choose a header image, selected from existing uploaded and default headers,
953          * or provide an array of uploaded header data (either new, or from media library).
954          *
955          * @param mixed $choice Which header image to select. Allows for values of 'random-default-image',
956          *      for randomly cycling among the default images; 'random-uploaded-image', for randomly cycling
957          *      among the uploaded images; the key of a default image registered for that theme; and
958          *      the key of an image uploaded for that theme (the basename of the URL).
959          *  Or an array of arguments: attachment_id, url, width, height. All are required.
960          *
961          * @since 3.4.0
962          */
963         final public function set_header_image( $choice ) {
964                 if ( is_array( $choice ) || is_object( $choice ) ) {
965                         $choice = (array) $choice;
966                         if ( ! isset( $choice['attachment_id'] ) || ! isset( $choice['url'] ) )
967                                 return;
968
969                         $choice['url'] = esc_url_raw( $choice['url'] );
970
971                         $header_image_data = (object) array(
972                                 'attachment_id' => $choice['attachment_id'],
973                                 'url'           => $choice['url'],
974                                 'thumbnail_url' => $choice['url'],
975                                 'height'        => $choice['height'],
976                                 'width'         => $choice['width'],
977                         );
978
979                         update_post_meta( $choice['attachment_id'], '_wp_attachment_is_custom_header', get_stylesheet() );
980                         set_theme_mod( 'header_image', $choice['url'] );
981                         set_theme_mod( 'header_image_data', $header_image_data );
982                         return;
983                 }
984
985                 if ( in_array( $choice, array( 'remove-header', 'random-default-image', 'random-uploaded-image' ) ) ) {
986                         set_theme_mod( 'header_image', $choice );
987                         remove_theme_mod( 'header_image_data' );
988                         return;
989                 }
990
991                 $uploaded = get_uploaded_header_images();
992                 if ( $uploaded && isset( $uploaded[ $choice ] ) ) {
993                         $header_image_data = $uploaded[ $choice ];
994
995                 } else {
996                         $this->process_default_headers();
997                         if ( isset( $this->default_headers[ $choice ] ) )
998                                 $header_image_data = $this->default_headers[ $choice ];
999                         else
1000                                 return;
1001                 }
1002
1003                 set_theme_mod( 'header_image', esc_url_raw( $header_image_data['url'] ) );
1004                 set_theme_mod( 'header_image_data', $header_image_data );
1005         }
1006
1007         /**
1008          * Remove a header image.
1009          *
1010          * @since 3.4.0
1011          */
1012         final public function remove_header_image() {
1013                 return $this->set_header_image( 'remove-header' );
1014         }
1015
1016         /**
1017          * Reset a header image to the default image for the theme.
1018          *
1019          * This method does not do anything if the theme does not have a default header image.
1020          *
1021          * @since 3.4.0
1022          */
1023         final public function reset_header_image() {
1024                 $this->process_default_headers();
1025                 $default = get_theme_support( 'custom-header', 'default-image' );
1026
1027                 if ( ! $default )
1028                         return $this->remove_header_image();
1029
1030                 $default = sprintf( $default, get_template_directory_uri(), get_stylesheet_directory_uri() );
1031
1032                 $default_data = array();
1033                 foreach ( $this->default_headers as $header => $details ) {
1034                         if ( $details['url'] == $default ) {
1035                                 $default_data = $details;
1036                                 break;
1037                         }
1038                 }
1039
1040                 set_theme_mod( 'header_image', $default );
1041                 set_theme_mod( 'header_image_data', (object) $default_data );
1042         }
1043 }