~canonical-sysadmins/wordpress/4.7.2

« back to all changes in this revision

Viewing changes to wp-admin/custom-header.php

  • Committer: Jacek Nykis
  • Date: 2015-01-05 16:17:05 UTC
  • Revision ID: jacek.nykis@canonical.com-20150105161705-w544l1h5mcg7u4w9
Initial commit

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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
        private $admin_header_callback;
 
26
 
 
27
        /**
 
28
         * Callback for header div.
 
29
         *
 
30
         * @var callback
 
31
         * @since 3.0.0
 
32
         * @access private
 
33
         */
 
34
        private $admin_image_div_callback;
 
35
 
 
36
        /**
 
37
         * Holds default headers.
 
38
         *
 
39
         * @var array
 
40
         * @since 3.0.0
 
41
         * @access private
 
42
         */
 
43
        private $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
        private $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
        private $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
        public 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
                add_action( 'customize_save_after',         array( $this, 'customize_set_last_used' ) );
 
78
                add_action( 'wp_ajax_custom-header-crop',   array( $this, 'ajax_header_crop'        ) );
 
79
                add_action( 'wp_ajax_custom-header-add',    array( $this, 'ajax_header_add'         ) );
 
80
                add_action( 'wp_ajax_custom-header-remove', array( $this, 'ajax_header_remove'      ) );
 
81
        }
 
82
 
 
83
        /**
 
84
         * Make private properties readable for backwards compatibility.
 
85
         *
 
86
         * @since 4.0.0
 
87
         * @access public
 
88
         *
 
89
         * @param string $name Property to get.
 
90
         * @return mixed Property.
 
91
         */
 
92
        public function __get( $name ) {
 
93
                return $this->$name;
 
94
        }
 
95
 
 
96
        /**
 
97
         * Make private properties settable for backwards compatibility.
 
98
         *
 
99
         * @since 4.0.0
 
100
         * @access public
 
101
         *
 
102
         * @param string $name  Property to set.
 
103
         * @param mixed  $value Property value.
 
104
         * @return mixed Newly-set property.
 
105
         */
 
106
        public function __set( $name, $value ) {
 
107
                return $this->$name = $value;
 
108
        }
 
109
 
 
110
        /**
 
111
         * Make private properties checkable for backwards compatibility.
 
112
         *
 
113
         * @since 4.0.0
 
114
         * @access public
 
115
         *
 
116
         * @param string $name Property to check if set.
 
117
         * @return bool Whether the property is set.
 
118
         */
 
119
        public function __isset( $name ) {
 
120
                return isset( $this->$name );
 
121
        }
 
122
 
 
123
        /**
 
124
         * Make private properties un-settable for backwards compatibility.
 
125
         *
 
126
         * @since 4.0.0
 
127
         * @access public
 
128
         *
 
129
         * @param string $name Property to unset.
 
130
         */
 
131
        public function __unset( $name ) {
 
132
                unset( $this->$name );
 
133
        }
 
134
 
 
135
        /**
 
136
         * Set up the hooks for the Custom Header admin page.
 
137
         *
 
138
         * @since 2.1.0
 
139
         */
 
140
        public function init() {
 
141
                if ( ! current_user_can('edit_theme_options') )
 
142
                        return;
 
143
 
 
144
                $this->page = $page = add_theme_page(__('Header'), __('Header'), 'edit_theme_options', 'custom-header', array($this, 'admin_page'));
 
145
 
 
146
                add_action("admin_print_scripts-$page", array($this, 'js_includes'));
 
147
                add_action("admin_print_styles-$page", array($this, 'css_includes'));
 
148
                add_action("admin_head-$page", array($this, 'help') );
 
149
                add_action("admin_head-$page", array($this, 'take_action'), 50);
 
150
                add_action("admin_head-$page", array($this, 'js'), 50);
 
151
                if ( $this->admin_header_callback )
 
152
                        add_action("admin_head-$page", $this->admin_header_callback, 51);
 
153
 
 
154
        }
 
155
 
 
156
        /**
 
157
         * Adds contextual help.
 
158
         *
 
159
         * @since 3.0.0
 
160
         */
 
161
        public function help() {
 
162
                get_current_screen()->add_help_tab( array(
 
163
                        'id'      => 'overview',
 
164
                        'title'   => __('Overview'),
 
165
                        'content' =>
 
166
                                '<p>' . __( 'This screen is used to customize the header section of your theme.') . '</p>' .
 
167
                                '<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>'
 
168
                ) );
 
169
 
 
170
                get_current_screen()->add_help_tab( array(
 
171
                        'id'      => 'set-header-image',
 
172
                        'title'   => __('Header Image'),
 
173
                        'content' =>
 
174
                                '<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>' .
 
175
                                '<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>' .
 
176
                                '<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>' .
 
177
                                '<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>'
 
178
                ) );
 
179
 
 
180
                get_current_screen()->add_help_tab( array(
 
181
                        'id'      => 'set-header-text',
 
182
                        'title'   => __('Header Text'),
 
183
                        'content' =>
 
184
                                '<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>' .
 
185
                                '<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>' .
 
186
                                '<p>' . __( 'Don&#8217;t forget to click &#8220;Save Changes&#8221; when you&#8217;re done!') . '</p>'
 
187
                ) );
 
188
 
 
189
                get_current_screen()->set_help_sidebar(
 
190
                        '<p><strong>' . __( 'For more information:' ) . '</strong></p>' .
 
191
                        '<p>' . __( '<a href="http://codex.wordpress.org/Appearance_Header_Screen" target="_blank">Documentation on Custom Header</a>' ) . '</p>' .
 
192
                        '<p>' . __( '<a href="https://wordpress.org/support/" target="_blank">Support Forums</a>' ) . '</p>'
 
193
                );
 
194
        }
 
195
 
 
196
        /**
 
197
         * Get the current step.
 
198
         *
 
199
         * @since 2.6.0
 
200
         *
 
201
         * @return int Current step
 
202
         */
 
203
        public function step() {
 
204
                if ( ! isset( $_GET['step'] ) )
 
205
                        return 1;
 
206
 
 
207
                $step = (int) $_GET['step'];
 
208
                if ( $step < 1 || 3 < $step ||
 
209
                        ( 2 == $step && ! wp_verify_nonce( $_REQUEST['_wpnonce-custom-header-upload'], 'custom-header-upload' ) ) ||
 
210
                        ( 3 == $step && ! wp_verify_nonce( $_REQUEST['_wpnonce'], 'custom-header-crop-image' ) )
 
211
                )
 
212
                        return 1;
 
213
 
 
214
                return $step;
 
215
        }
 
216
 
 
217
        /**
 
218
         * Set up the enqueue for the JavaScript files.
 
219
         *
 
220
         * @since 2.1.0
 
221
         */
 
222
        public function js_includes() {
 
223
                $step = $this->step();
 
224
 
 
225
                if ( ( 1 == $step || 3 == $step ) ) {
 
226
                        wp_enqueue_media();
 
227
                        wp_enqueue_script( 'custom-header' );
 
228
                        if ( current_theme_supports( 'custom-header', 'header-text' ) )
 
229
                                wp_enqueue_script( 'wp-color-picker' );
 
230
                } elseif ( 2 == $step ) {
 
231
                        wp_enqueue_script('imgareaselect');
 
232
                }
 
233
        }
 
234
 
 
235
        /**
 
236
         * Set up the enqueue for the CSS files
 
237
         *
 
238
         * @since 2.7.0
 
239
         */
 
240
        public function css_includes() {
 
241
                $step = $this->step();
 
242
 
 
243
                if ( ( 1 == $step || 3 == $step ) && current_theme_supports( 'custom-header', 'header-text' ) )
 
244
                        wp_enqueue_style( 'wp-color-picker' );
 
245
                elseif ( 2 == $step )
 
246
                        wp_enqueue_style('imgareaselect');
 
247
        }
 
248
 
 
249
        /**
 
250
         * Execute custom header modification.
 
251
         *
 
252
         * @since 2.6.0
 
253
         */
 
254
        public function take_action() {
 
255
                if ( ! current_user_can('edit_theme_options') )
 
256
                        return;
 
257
 
 
258
                if ( empty( $_POST ) )
 
259
                        return;
 
260
 
 
261
                $this->updated = true;
 
262
 
 
263
                if ( isset( $_POST['resetheader'] ) ) {
 
264
                        check_admin_referer( 'custom-header-options', '_wpnonce-custom-header-options' );
 
265
                        $this->reset_header_image();
 
266
                        return;
 
267
                }
 
268
 
 
269
                if ( isset( $_POST['removeheader'] ) ) {
 
270
                        check_admin_referer( 'custom-header-options', '_wpnonce-custom-header-options' );
 
271
                        $this->remove_header_image();
 
272
                        return;
 
273
                }
 
274
 
 
275
                if ( isset( $_POST['text-color'] ) && ! isset( $_POST['display-header-text'] ) ) {
 
276
                        check_admin_referer( 'custom-header-options', '_wpnonce-custom-header-options' );
 
277
                        set_theme_mod( 'header_textcolor', 'blank' );
 
278
                } elseif ( isset( $_POST['text-color'] ) ) {
 
279
                        check_admin_referer( 'custom-header-options', '_wpnonce-custom-header-options' );
 
280
                        $_POST['text-color'] = str_replace( '#', '', $_POST['text-color'] );
 
281
                        $color = preg_replace('/[^0-9a-fA-F]/', '', $_POST['text-color']);
 
282
                        if ( strlen($color) == 6 || strlen($color) == 3 )
 
283
                                set_theme_mod('header_textcolor', $color);
 
284
                        elseif ( ! $color )
 
285
                                set_theme_mod( 'header_textcolor', 'blank' );
 
286
                }
 
287
 
 
288
                if ( isset( $_POST['default-header'] ) ) {
 
289
                        check_admin_referer( 'custom-header-options', '_wpnonce-custom-header-options' );
 
290
                        $this->set_header_image( $_POST['default-header'] );
 
291
                        return;
 
292
                }
 
293
        }
 
294
 
 
295
        /**
 
296
         * Process the default headers
 
297
         *
 
298
         * @since 3.0.0
 
299
         */
 
300
        public function process_default_headers() {
 
301
                global $_wp_default_headers;
 
302
 
 
303
                if ( !empty($this->headers) )
 
304
                        return;
 
305
 
 
306
                if ( !isset($_wp_default_headers) )
 
307
                        return;
 
308
 
 
309
                if ( ! empty( $this->default_headers ) ) {
 
310
                        return;
 
311
                }
 
312
 
 
313
                $this->default_headers = $_wp_default_headers;
 
314
                $template_directory_uri = get_template_directory_uri();
 
315
                $stylesheet_directory_uri = get_stylesheet_directory_uri();
 
316
                foreach ( array_keys($this->default_headers) as $header ) {
 
317
                        $this->default_headers[$header]['url'] =  sprintf( $this->default_headers[$header]['url'], $template_directory_uri, $stylesheet_directory_uri );
 
318
                        $this->default_headers[$header]['thumbnail_url'] =  sprintf( $this->default_headers[$header]['thumbnail_url'], $template_directory_uri, $stylesheet_directory_uri );
 
319
                }
 
320
        }
 
321
 
 
322
        /**
 
323
         * Display UI for selecting one of several default headers.
 
324
         *
 
325
         * Show the random image option if this theme has multiple header images.
 
326
         * Random image option is on by default if no header has been set.
 
327
         *
 
328
         * @since 3.0.0
 
329
         */
 
330
        public function show_header_selector( $type = 'default' ) {
 
331
                if ( 'default' == $type ) {
 
332
                        $headers = $this->default_headers;
 
333
                } else {
 
334
                        $headers = get_uploaded_header_images();
 
335
                        $type = 'uploaded';
 
336
                }
 
337
 
 
338
                if ( 1 < count( $headers ) ) {
 
339
                        echo '<div class="random-header">';
 
340
                        echo '<label><input name="default-header" type="radio" value="random-' . $type . '-image"' . checked( is_random_header_image( $type ), true, false ) . ' />';
 
341
                        echo __( '<strong>Random:</strong> Show a different image on each page.' );
 
342
                        echo '</label>';
 
343
                        echo '</div>';
 
344
                }
 
345
 
 
346
                echo '<div class="available-headers">';
 
347
                foreach ( $headers as $header_key => $header ) {
 
348
                        $header_thumbnail = $header['thumbnail_url'];
 
349
                        $header_url = $header['url'];
 
350
                        $header_desc = empty( $header['description'] ) ? '' : $header['description'];
 
351
                        echo '<div class="default-header">';
 
352
                        echo '<label><input name="default-header" type="radio" value="' . esc_attr( $header_key ) . '" ' . checked( $header_url, get_theme_mod( 'header_image' ), false ) . ' />';
 
353
                        $width = '';
 
354
                        if ( !empty( $header['attachment_id'] ) )
 
355
                                $width = ' width="230"';
 
356
                        echo '<img src="' . set_url_scheme( $header_thumbnail ) . '" alt="' . esc_attr( $header_desc ) .'" title="' . esc_attr( $header_desc ) . '"' . $width . ' /></label>';
 
357
                        echo '</div>';
 
358
                }
 
359
                echo '<div class="clear"></div></div>';
 
360
        }
 
361
 
 
362
        /**
 
363
         * Execute Javascript depending on step.
 
364
         *
 
365
         * @since 2.1.0
 
366
         */
 
367
        public function js() {
 
368
                $step = $this->step();
 
369
                if ( ( 1 == $step || 3 == $step ) && current_theme_supports( 'custom-header', 'header-text' ) )
 
370
                        $this->js_1();
 
371
                elseif ( 2 == $step )
 
372
                        $this->js_2();
 
373
        }
 
374
 
 
375
        /**
 
376
         * Display Javascript based on Step 1 and 3.
 
377
         *
 
378
         * @since 2.6.0
 
379
         */
 
380
        public function js_1() {
 
381
                $default_color = '';
 
382
                if ( current_theme_supports( 'custom-header', 'default-text-color' ) ) {
 
383
                        $default_color = get_theme_support( 'custom-header', 'default-text-color' );
 
384
                        if ( $default_color && false === strpos( $default_color, '#' ) ) {
 
385
                                $default_color = '#' . $default_color;
 
386
                        }
 
387
                }
 
388
                ?>
 
389
 
 
390
<script type="text/javascript">
 
391
/* <![CDATA[ */
 
392
(function($){
 
393
        var default_color = '<?php echo $default_color; ?>',
 
394
                header_text_fields;
 
395
 
 
396
        function pickColor(color) {
 
397
                $('#name').css('color', color);
 
398
                $('#desc').css('color', color);
 
399
                $('#text-color').val(color);
 
400
        }
 
401
 
 
402
        function toggle_text() {
 
403
                var checked = $('#display-header-text').prop('checked'),
 
404
                        text_color;
 
405
                header_text_fields.toggle( checked );
 
406
                if ( ! checked )
 
407
                        return;
 
408
                text_color = $('#text-color');
 
409
                if ( '' == text_color.val().replace('#', '') ) {
 
410
                        text_color.val( default_color );
 
411
                        pickColor( default_color );
 
412
                } else {
 
413
                        pickColor( text_color.val() );
 
414
                }
 
415
        }
 
416
 
 
417
        $(document).ready(function() {
 
418
                var text_color = $('#text-color');
 
419
                header_text_fields = $('.displaying-header-text');
 
420
                text_color.wpColorPicker({
 
421
                        change: function( event, ui ) {
 
422
                                pickColor( text_color.wpColorPicker('color') );
 
423
                        },
 
424
                        clear: function() {
 
425
                                pickColor( '' );
 
426
                        }
 
427
                });
 
428
                $('#display-header-text').click( toggle_text );
 
429
                <?php if ( ! display_header_text() ) : ?>
 
430
                toggle_text();
 
431
                <?php endif; ?>
 
432
        });
 
433
})(jQuery);
 
434
/* ]]> */
 
435
</script>
 
436
<?php
 
437
        }
 
438
 
 
439
        /**
 
440
         * Display Javascript based on Step 2.
 
441
         *
 
442
         * @since 2.6.0
 
443
         */
 
444
        public function js_2() { ?>
 
445
<script type="text/javascript">
 
446
/* <![CDATA[ */
 
447
        function onEndCrop( coords ) {
 
448
                jQuery( '#x1' ).val(coords.x);
 
449
                jQuery( '#y1' ).val(coords.y);
 
450
                jQuery( '#width' ).val(coords.w);
 
451
                jQuery( '#height' ).val(coords.h);
 
452
        }
 
453
 
 
454
        jQuery(document).ready(function() {
 
455
                var xinit = <?php echo absint( get_theme_support( 'custom-header', 'width' ) ); ?>;
 
456
                var yinit = <?php echo absint( get_theme_support( 'custom-header', 'height' ) ); ?>;
 
457
                var ratio = xinit / yinit;
 
458
                var ximg = jQuery('img#upload').width();
 
459
                var yimg = jQuery('img#upload').height();
 
460
 
 
461
                if ( yimg < yinit || ximg < xinit ) {
 
462
                        if ( ximg / yimg > ratio ) {
 
463
                                yinit = yimg;
 
464
                                xinit = yinit * ratio;
 
465
                        } else {
 
466
                                xinit = ximg;
 
467
                                yinit = xinit / ratio;
 
468
                        }
 
469
                }
 
470
 
 
471
                jQuery('img#upload').imgAreaSelect({
 
472
                        handles: true,
 
473
                        keys: true,
 
474
                        show: true,
 
475
                        x1: 0,
 
476
                        y1: 0,
 
477
                        x2: xinit,
 
478
                        y2: yinit,
 
479
                        <?php
 
480
                        if ( ! current_theme_supports( 'custom-header', 'flex-height' ) && ! current_theme_supports( 'custom-header', 'flex-width' ) ) {
 
481
                        ?>
 
482
                        aspectRatio: xinit + ':' + yinit,
 
483
                        <?php
 
484
                        }
 
485
                        if ( ! current_theme_supports( 'custom-header', 'flex-height' ) ) {
 
486
                        ?>
 
487
                        maxHeight: <?php echo get_theme_support( 'custom-header', 'height' ); ?>,
 
488
                        <?php
 
489
                        }
 
490
                        if ( ! current_theme_supports( 'custom-header', 'flex-width' ) ) {
 
491
                        ?>
 
492
                        maxWidth: <?php echo get_theme_support( 'custom-header', 'width' ); ?>,
 
493
                        <?php
 
494
                        }
 
495
                        ?>
 
496
                        onInit: function () {
 
497
                                jQuery('#width').val(xinit);
 
498
                                jQuery('#height').val(yinit);
 
499
                        },
 
500
                        onSelectChange: function(img, c) {
 
501
                                jQuery('#x1').val(c.x1);
 
502
                                jQuery('#y1').val(c.y1);
 
503
                                jQuery('#width').val(c.width);
 
504
                                jQuery('#height').val(c.height);
 
505
                        }
 
506
                });
 
507
        });
 
508
/* ]]> */
 
509
</script>
 
510
<?php
 
511
        }
 
512
 
 
513
        /**
 
514
         * Display first step of custom header image page.
 
515
         *
 
516
         * @since 2.1.0
 
517
         */
 
518
        public function step_1() {
 
519
                $this->process_default_headers();
 
520
?>
 
521
 
 
522
<div class="wrap">
 
523
<h2><?php _e( 'Custom Header' ); ?></h2>
 
524
 
 
525
<?php if ( ! empty( $this->updated ) ) { ?>
 
526
<div id="message" class="updated">
 
527
<p><?php printf( __( 'Header updated. <a href="%s">Visit your site</a> to see how it looks.' ), home_url( '/' ) ); ?></p>
 
528
</div>
 
529
<?php } ?>
 
530
 
 
531
<h3><?php _e( 'Header Image' ); ?></h3>
 
532
 
 
533
<table class="form-table">
 
534
<tbody>
 
535
 
 
536
<?php if ( get_custom_header() || display_header_text() ) : ?>
 
537
<tr>
 
538
<th scope="row"><?php _e( 'Preview' ); ?></th>
 
539
<td>
 
540
        <?php
 
541
        if ( $this->admin_image_div_callback ) {
 
542
                call_user_func( $this->admin_image_div_callback );
 
543
        } else {
 
544
                $custom_header = get_custom_header();
 
545
                $header_image_style = 'background-image:url(' . esc_url( get_header_image() ) . ');';
 
546
                if ( $custom_header->width )
 
547
                        $header_image_style .= 'max-width:' . $custom_header->width . 'px;';
 
548
                if ( $custom_header->height )
 
549
                        $header_image_style .= 'height:' . $custom_header->height . 'px;';
 
550
        ?>
 
551
        <div id="headimg" style="<?php echo $header_image_style; ?>">
 
552
                <?php
 
553
                if ( display_header_text() )
 
554
                        $style = ' style="color:#' . get_header_textcolor() . ';"';
 
555
                else
 
556
                        $style = ' style="display:none;"';
 
557
                ?>
 
558
                <h1><a id="name" class="displaying-header-text" <?php echo $style; ?> onclick="return false;" href="<?php bloginfo('url'); ?>"><?php bloginfo( 'name' ); ?></a></h1>
 
559
                <div id="desc" class="displaying-header-text" <?php echo $style; ?>><?php bloginfo( 'description' ); ?></div>
 
560
        </div>
 
561
        <?php } ?>
 
562
</td>
 
563
</tr>
 
564
<?php endif; ?>
 
565
 
 
566
<?php if ( current_theme_supports( 'custom-header', 'uploads' ) ) : ?>
 
567
<tr>
 
568
<th scope="row"><?php _e( 'Select Image' ); ?></th>
 
569
<td>
 
570
        <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 />
 
571
        <?php
 
572
        if ( ! current_theme_supports( 'custom-header', 'flex-height' ) && ! current_theme_supports( 'custom-header', 'flex-width' ) ) {
 
573
                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' ) );
 
574
        } elseif ( current_theme_supports( 'custom-header', 'flex-height' ) ) {
 
575
                if ( ! current_theme_supports( 'custom-header', 'flex-width' ) )
 
576
                        printf( __( 'Images should be at least <strong>%1$d pixels</strong> wide.' ) . ' ', get_theme_support( 'custom-header', 'width' ) );
 
577
        } elseif ( current_theme_supports( 'custom-header', 'flex-width' ) ) {
 
578
                if ( ! current_theme_supports( 'custom-header', 'flex-height' ) )
 
579
                        printf( __( 'Images should be at least <strong>%1$d pixels</strong> tall.' ) . ' ', get_theme_support( 'custom-header', 'height' ) );
 
580
        }
 
581
        if ( current_theme_supports( 'custom-header', 'flex-height' ) || current_theme_supports( 'custom-header', 'flex-width' ) ) {
 
582
                if ( current_theme_supports( 'custom-header', 'width' ) )
 
583
                        printf( __( 'Suggested width is <strong>%1$d pixels</strong>.' ) . ' ', get_theme_support( 'custom-header', 'width' ) );
 
584
                if ( current_theme_supports( 'custom-header', 'height' ) )
 
585
                        printf( __( 'Suggested height is <strong>%1$d pixels</strong>.' ) . ' ', get_theme_support( 'custom-header', 'height' ) );
 
586
        }
 
587
        ?></p>
 
588
        <form enctype="multipart/form-data" id="upload-form" class="wp-upload-form" method="post" action="<?php echo esc_url( add_query_arg( 'step', 2 ) ) ?>">
 
589
        <p>
 
590
                <label for="upload"><?php _e( 'Choose an image from your computer:' ); ?></label><br />
 
591
                <input type="file" id="upload" name="import" />
 
592
                <input type="hidden" name="action" value="save" />
 
593
                <?php wp_nonce_field( 'custom-header-upload', '_wpnonce-custom-header-upload' ); ?>
 
594
                <?php submit_button( __( 'Upload' ), 'button', 'submit', false ); ?>
 
595
        </p>
 
596
        <?php
 
597
                $modal_update_href = esc_url( add_query_arg( array(
 
598
                        'page' => 'custom-header',
 
599
                        'step' => 2,
 
600
                        '_wpnonce-custom-header-upload' => wp_create_nonce('custom-header-upload'),
 
601
                ), admin_url('themes.php') ) );
 
602
        ?>
 
603
        <p>
 
604
                <label for="choose-from-library-link"><?php _e( 'Or choose an image from your media library:' ); ?></label><br />
 
605
                <a id="choose-from-library-link" class="button"
 
606
                        data-update-link="<?php echo esc_attr( $modal_update_href ); ?>"
 
607
                        data-choose="<?php esc_attr_e( 'Choose a Custom Header' ); ?>"
 
608
                        data-update="<?php esc_attr_e( 'Set as header' ); ?>"><?php _e( 'Choose Image' ); ?></a>
 
609
        </p>
 
610
        </form>
 
611
</td>
 
612
</tr>
 
613
<?php endif; ?>
 
614
</tbody>
 
615
</table>
 
616
 
 
617
<form method="post" action="<?php echo esc_url( add_query_arg( 'step', 1 ) ) ?>">
 
618
<table class="form-table">
 
619
<tbody>
 
620
        <?php if ( get_uploaded_header_images() ) : ?>
 
621
<tr>
 
622
<th scope="row"><?php _e( 'Uploaded Images' ); ?></th>
 
623
<td>
 
624
        <p><?php _e( 'You can choose one of your previously uploaded headers, or show a random one.' ) ?></p>
 
625
        <?php
 
626
                $this->show_header_selector( 'uploaded' );
 
627
        ?>
 
628
</td>
 
629
</tr>
 
630
        <?php endif;
 
631
        if ( ! empty( $this->default_headers ) ) : ?>
 
632
<tr>
 
633
<th scope="row"><?php _e( 'Default Images' ); ?></th>
 
634
<td>
 
635
<?php if ( current_theme_supports( 'custom-header', 'uploads' ) ) : ?>
 
636
        <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>
 
637
<?php else: ?>
 
638
        <p><?php _e( 'You can use one of these cool headers or show a random one on each page.' ) ?></p>
 
639
<?php endif; ?>
 
640
        <?php
 
641
                $this->show_header_selector( 'default' );
 
642
        ?>
 
643
</td>
 
644
</tr>
 
645
        <?php endif;
 
646
        if ( get_header_image() ) : ?>
 
647
<tr>
 
648
<th scope="row"><?php _e( 'Remove Image' ); ?></th>
 
649
<td>
 
650
        <p><?php _e( 'This will remove the header image. You will not be able to restore any customizations.' ) ?></p>
 
651
        <?php submit_button( __( 'Remove Header Image' ), 'button', 'removeheader', false ); ?>
 
652
</td>
 
653
</tr>
 
654
        <?php endif;
 
655
 
 
656
        $default_image = get_theme_support( 'custom-header', 'default-image' );
 
657
        if ( $default_image && get_header_image() != $default_image ) : ?>
 
658
<tr>
 
659
<th scope="row"><?php _e( 'Reset Image' ); ?></th>
 
660
<td>
 
661
        <p><?php _e( 'This will restore the original header image. You will not be able to restore any customizations.' ) ?></p>
 
662
        <?php submit_button( __( 'Restore Original Header Image' ), 'button', 'resetheader', false ); ?>
 
663
</td>
 
664
</tr>
 
665
        <?php endif; ?>
 
666
</tbody>
 
667
</table>
 
668
 
 
669
<?php if ( current_theme_supports( 'custom-header', 'header-text' ) ) : ?>
 
670
 
 
671
<h3><?php _e( 'Header Text' ); ?></h3>
 
672
 
 
673
<table class="form-table">
 
674
<tbody>
 
675
<tr>
 
676
<th scope="row"><?php _e( 'Header Text' ); ?></th>
 
677
<td>
 
678
        <p>
 
679
        <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>
 
680
        </p>
 
681
</td>
 
682
</tr>
 
683
 
 
684
<tr class="displaying-header-text">
 
685
<th scope="row"><?php _e( 'Text Color' ); ?></th>
 
686
<td>
 
687
        <p>
 
688
        <?php
 
689
        $default_color = '';
 
690
        if ( current_theme_supports( 'custom-header', 'default-text-color' ) ) {
 
691
                $default_color = get_theme_support( 'custom-header', 'default-text-color' );
 
692
                if ( $default_color && false === strpos( $default_color, '#' ) ) {
 
693
                        $default_color = '#' . $default_color;
 
694
                }
 
695
        }
 
696
 
 
697
        $default_color_attr = $default_color ? ' data-default-color="' . esc_attr( $default_color ) . '"' : '';
 
698
 
 
699
        $header_textcolor = display_header_text() ? get_header_textcolor() : get_theme_support( 'custom-header', 'default-text-color' );
 
700
        if ( $header_textcolor && false === strpos( $header_textcolor, '#' ) ) {
 
701
                $header_textcolor = '#' . $header_textcolor;
 
702
        }
 
703
 
 
704
        echo '<input type="text" name="text-color" id="text-color" value="' . esc_attr( $header_textcolor ) . '"' . $default_color_attr . ' />';
 
705
        if ( $default_color ) {
 
706
                echo ' <span class="description hide-if-js">' . sprintf( _x( 'Default: %s', 'color' ), esc_html( $default_color ) ) . '</span>';
 
707
        }
 
708
        ?>
 
709
        </p>
 
710
</td>
 
711
</tr>
 
712
</tbody>
 
713
</table>
 
714
<?php endif;
 
715
 
 
716
/**
 
717
 * Fires just before the submit button in the custom header options form.
 
718
 *
 
719
 * @since 3.1.0
 
720
 */
 
721
do_action( 'custom_header_options' );
 
722
 
 
723
wp_nonce_field( 'custom-header-options', '_wpnonce-custom-header-options' ); ?>
 
724
 
 
725
<?php submit_button( null, 'primary', 'save-header-options' ); ?>
 
726
</form>
 
727
</div>
 
728
 
 
729
<?php }
 
730
 
 
731
        /**
 
732
         * Display second step of custom header image page.
 
733
         *
 
734
         * @since 2.1.0
 
735
         */
 
736
        public function step_2() {
 
737
                check_admin_referer('custom-header-upload', '_wpnonce-custom-header-upload');
 
738
                if ( ! current_theme_supports( 'custom-header', 'uploads' ) )
 
739
                        wp_die( __( 'Cheatin&#8217; uh?' ) );
 
740
 
 
741
                if ( empty( $_POST ) && isset( $_GET['file'] ) ) {
 
742
                        $attachment_id = absint( $_GET['file'] );
 
743
                        $file = get_attached_file( $attachment_id, true );
 
744
                        $url = wp_get_attachment_image_src( $attachment_id, 'full' );
 
745
                        $url = $url[0];
 
746
                } elseif ( isset( $_POST ) ) {
 
747
                        $data = $this->step_2_manage_upload();
 
748
                        $attachment_id = $data['attachment_id'];
 
749
                        $file = $data['file'];
 
750
                        $url = $data['url'];
 
751
                        $type = $data['type'];
 
752
                }
 
753
 
 
754
                if ( file_exists( $file ) ) {
 
755
                        list( $width, $height, $type, $attr ) = getimagesize( $file );
 
756
                } else {
 
757
                        $data = wp_get_attachment_metadata( $attachment_id );
 
758
                        $height = isset( $data[ 'height' ] ) ? $data[ 'height' ] : 0;
 
759
                        $width = isset( $data[ 'width' ] ) ? $data[ 'width' ] : 0;
 
760
                        unset( $data );
 
761
                }
 
762
 
 
763
                $max_width = 0;
 
764
                // For flex, limit size of image displayed to 1500px unless theme says otherwise
 
765
                if ( current_theme_supports( 'custom-header', 'flex-width' ) )
 
766
                        $max_width = 1500;
 
767
 
 
768
                if ( current_theme_supports( 'custom-header', 'max-width' ) )
 
769
                        $max_width = max( $max_width, get_theme_support( 'custom-header', 'max-width' ) );
 
770
                $max_width = max( $max_width, get_theme_support( 'custom-header', 'width' ) );
 
771
 
 
772
                // If flexible height isn't supported and the image is the exact right size
 
773
                if ( ! current_theme_supports( 'custom-header', 'flex-height' ) && ! current_theme_supports( 'custom-header', 'flex-width' )
 
774
                        && $width == get_theme_support( 'custom-header', 'width' ) && $height == get_theme_support( 'custom-header', 'height' ) )
 
775
                {
 
776
                        // Add the meta-data
 
777
                        if ( file_exists( $file ) )
 
778
                                wp_update_attachment_metadata( $attachment_id, wp_generate_attachment_metadata( $attachment_id, $file ) );
 
779
 
 
780
                        $this->set_header_image( compact( 'url', 'attachment_id', 'width', 'height' ) );
 
781
 
 
782
                        /**
 
783
                         * Fires after the header image is set or an error is returned.
 
784
                         *
 
785
                         * @since 2.1.0
 
786
                         *
 
787
                         * @param string $file          Path to the file.
 
788
                         * @param int    $attachment_id Attachment ID.
 
789
                         */
 
790
                        do_action( 'wp_create_file_in_uploads', $file, $attachment_id ); // For replication
 
791
 
 
792
                        return $this->finished();
 
793
                } elseif ( $width > $max_width ) {
 
794
                        $oitar = $width / $max_width;
 
795
                        $image = wp_crop_image($attachment_id, 0, 0, $width, $height, $max_width, $height / $oitar, false, str_replace(basename($file), 'midsize-'.basename($file), $file));
 
796
                        if ( ! $image || is_wp_error( $image ) )
 
797
                                wp_die( __( 'Image could not be processed. Please go back and try again.' ), __( 'Image Processing Error' ) );
 
798
 
 
799
                        /** This filter is documented in wp-admin/custom-header.php */
 
800
                        $image = apply_filters( 'wp_create_file_in_uploads', $image, $attachment_id ); // For replication
 
801
 
 
802
                        $url = str_replace(basename($url), basename($image), $url);
 
803
                        $width = $width / $oitar;
 
804
                        $height = $height / $oitar;
 
805
                } else {
 
806
                        $oitar = 1;
 
807
                }
 
808
                ?>
 
809
 
 
810
<div class="wrap">
 
811
<h2><?php _e( 'Crop Header Image' ); ?></h2>
 
812
 
 
813
<form method="post" action="<?php echo esc_url(add_query_arg('step', 3)); ?>">
 
814
        <p class="hide-if-no-js"><?php _e('Choose the part of the image you want to use as your header.'); ?></p>
 
815
        <p class="hide-if-js"><strong><?php _e( 'You need Javascript to choose a part of the image.'); ?></strong></p>
 
816
 
 
817
        <div id="crop_image" style="position: relative">
 
818
                <img src="<?php echo esc_url( $url ); ?>" id="upload" width="<?php echo $width; ?>" height="<?php echo $height; ?>" />
 
819
        </div>
 
820
 
 
821
        <input type="hidden" name="x1" id="x1" value="0"/>
 
822
        <input type="hidden" name="y1" id="y1" value="0"/>
 
823
        <input type="hidden" name="width" id="width" value="<?php echo esc_attr( $width ); ?>"/>
 
824
        <input type="hidden" name="height" id="height" value="<?php echo esc_attr( $height ); ?>"/>
 
825
        <input type="hidden" name="attachment_id" id="attachment_id" value="<?php echo esc_attr( $attachment_id ); ?>" />
 
826
        <input type="hidden" name="oitar" id="oitar" value="<?php echo esc_attr( $oitar ); ?>" />
 
827
        <?php if ( empty( $_POST ) && isset( $_GET['file'] ) ) { ?>
 
828
        <input type="hidden" name="create-new-attachment" value="true" />
 
829
        <?php } ?>
 
830
        <?php wp_nonce_field( 'custom-header-crop-image' ) ?>
 
831
 
 
832
        <p class="submit">
 
833
        <?php submit_button( __( 'Crop and Publish' ), 'primary', 'submit', false ); ?>
 
834
        <?php
 
835
        if ( isset( $oitar ) && 1 == $oitar && ( current_theme_supports( 'custom-header', 'flex-height' ) || current_theme_supports( 'custom-header', 'flex-width' ) ) )
 
836
                submit_button( __( 'Skip Cropping, Publish Image as Is' ), 'secondary', 'skip-cropping', false );
 
837
        ?>
 
838
        </p>
 
839
</form>
 
840
</div>
 
841
                <?php
 
842
        }
 
843
 
 
844
 
 
845
        /**
 
846
         * Upload the file to be cropped in the second step.
 
847
         *
 
848
         * @since 3.4.0
 
849
         */
 
850
        public function step_2_manage_upload() {
 
851
                $overrides = array('test_form' => false);
 
852
 
 
853
                $uploaded_file = $_FILES['import'];
 
854
                $wp_filetype = wp_check_filetype_and_ext( $uploaded_file['tmp_name'], $uploaded_file['name'], false );
 
855
                if ( ! wp_match_mime_types( 'image', $wp_filetype['type'] ) )
 
856
                        wp_die( __( 'The uploaded file is not a valid image. Please try again.' ) );
 
857
 
 
858
                $file = wp_handle_upload($uploaded_file, $overrides);
 
859
 
 
860
                if ( isset($file['error']) )
 
861
                        wp_die( $file['error'],  __( 'Image Upload Error' ) );
 
862
 
 
863
                $url = $file['url'];
 
864
                $type = $file['type'];
 
865
                $file = $file['file'];
 
866
                $filename = basename($file);
 
867
 
 
868
                // Construct the object array
 
869
                $object = array(
 
870
                        'post_title'     => $filename,
 
871
                        'post_content'   => $url,
 
872
                        'post_mime_type' => $type,
 
873
                        'guid'           => $url,
 
874
                        'context'        => 'custom-header'
 
875
                );
 
876
 
 
877
                // Save the data
 
878
                $attachment_id = wp_insert_attachment( $object, $file );
 
879
                return compact( 'attachment_id', 'file', 'filename', 'url', 'type' );
 
880
        }
 
881
 
 
882
        /**
 
883
         * Display third step of custom header image page.
 
884
         *
 
885
         * @since 2.1.0
 
886
         */
 
887
        public function step_3() {
 
888
                check_admin_referer( 'custom-header-crop-image' );
 
889
 
 
890
                if ( ! current_theme_supports( 'custom-header', 'uploads' ) )
 
891
                        wp_die( __( 'Cheatin&#8217; uh?' ) );
 
892
 
 
893
                if ( ! empty( $_POST['skip-cropping'] ) && ! ( current_theme_supports( 'custom-header', 'flex-height' ) || current_theme_supports( 'custom-header', 'flex-width' ) ) )
 
894
                        wp_die( __( 'Cheatin&#8217; uh?' ) );
 
895
 
 
896
                if ( $_POST['oitar'] > 1 ) {
 
897
                        $_POST['x1'] = $_POST['x1'] * $_POST['oitar'];
 
898
                        $_POST['y1'] = $_POST['y1'] * $_POST['oitar'];
 
899
                        $_POST['width'] = $_POST['width'] * $_POST['oitar'];
 
900
                        $_POST['height'] = $_POST['height'] * $_POST['oitar'];
 
901
                }
 
902
 
 
903
                $attachment_id = absint( $_POST['attachment_id'] );
 
904
                $original = get_attached_file($attachment_id);
 
905
 
 
906
                $dimensions = $this->get_header_dimensions( array(
 
907
                        'height' => $_POST['height'],
 
908
                        'width'  => $_POST['width'],
 
909
                ) );
 
910
                $height = $dimensions['dst_height'];
 
911
                $width = $dimensions['dst_width'];
 
912
 
 
913
                if ( empty( $_POST['skip-cropping'] ) )
 
914
                        $cropped = wp_crop_image( $attachment_id, (int) $_POST['x1'], (int) $_POST['y1'], (int) $_POST['width'], (int) $_POST['height'], $width, $height );
 
915
                elseif ( ! empty( $_POST['create-new-attachment'] ) )
 
916
                        $cropped = _copy_image_file( $attachment_id );
 
917
                else
 
918
                        $cropped = get_attached_file( $attachment_id );
 
919
 
 
920
                if ( ! $cropped || is_wp_error( $cropped ) )
 
921
                        wp_die( __( 'Image could not be processed. Please go back and try again.' ), __( 'Image Processing Error' ) );
 
922
 
 
923
                /** This filter is documented in wp-admin/custom-header.php */
 
924
                $cropped = apply_filters( 'wp_create_file_in_uploads', $cropped, $attachment_id ); // For replication
 
925
 
 
926
                $object = $this->create_attachment_object( $cropped, $attachment_id );
 
927
 
 
928
                if ( ! empty( $_POST['create-new-attachment'] ) )
 
929
                        unset( $object['ID'] );
 
930
 
 
931
                // Update the attachment
 
932
                $attachment_id = $this->insert_attachment( $object, $cropped );
 
933
 
 
934
                $url = $object['guid'];
 
935
                $this->set_header_image( compact( 'url', 'attachment_id', 'width', 'height' ) );
 
936
 
 
937
                // Cleanup.
 
938
                $medium = str_replace( basename( $original ), 'midsize-' . basename( $original ), $original );
 
939
                if ( file_exists( $medium ) ) {
 
940
                        /**
 
941
                         * Filter the path of the file to delete.
 
942
                         *
 
943
                         * @since 2.1.0
 
944
                         *
 
945
                         * @param string $medium Path to the file to delete.
 
946
                         */
 
947
                        @unlink( apply_filters( 'wp_delete_file', $medium ) );
 
948
                }
 
949
 
 
950
                if ( empty( $_POST['create-new-attachment'] ) && empty( $_POST['skip-cropping'] ) ) {
 
951
                        /** This filter is documented in wp-admin/custom-header.php */
 
952
                        @unlink( apply_filters( 'wp_delete_file', $original ) );
 
953
                }
 
954
 
 
955
                return $this->finished();
 
956
        }
 
957
 
 
958
        /**
 
959
         * Display last step of custom header image page.
 
960
         *
 
961
         * @since 2.1.0
 
962
         */
 
963
        public function finished() {
 
964
                $this->updated = true;
 
965
                $this->step_1();
 
966
        }
 
967
 
 
968
        /**
 
969
         * Display the page based on the current step.
 
970
         *
 
971
         * @since 2.1.0
 
972
         */
 
973
        public function admin_page() {
 
974
                if ( ! current_user_can('edit_theme_options') )
 
975
                        wp_die(__('You do not have permission to customize headers.'));
 
976
                $step = $this->step();
 
977
                if ( 2 == $step )
 
978
                        $this->step_2();
 
979
                elseif ( 3 == $step )
 
980
                        $this->step_3();
 
981
                else
 
982
                        $this->step_1();
 
983
        }
 
984
 
 
985
        /**
 
986
         * Unused since 3.5.0.
 
987
         *
 
988
         * @since 3.4.0
 
989
         */
 
990
        public function attachment_fields_to_edit( $form_fields ) {
 
991
                return $form_fields;
 
992
        }
 
993
 
 
994
        /**
 
995
         * Unused since 3.5.0.
 
996
         *
 
997
         * @since 3.4.0
 
998
         */
 
999
        public function filter_upload_tabs( $tabs ) {
 
1000
                return $tabs;
 
1001
        }
 
1002
 
 
1003
        /**
 
1004
         * Choose a header image, selected from existing uploaded and default headers,
 
1005
         * or provide an array of uploaded header data (either new, or from media library).
 
1006
         *
 
1007
         * @param mixed $choice Which header image to select. Allows for values of 'random-default-image',
 
1008
         *      for randomly cycling among the default images; 'random-uploaded-image', for randomly cycling
 
1009
         *      among the uploaded images; the key of a default image registered for that theme; and
 
1010
         *      the key of an image uploaded for that theme (the basename of the URL).
 
1011
         *  Or an array of arguments: attachment_id, url, width, height. All are required.
 
1012
         *
 
1013
         * @since 3.4.0
 
1014
         */
 
1015
        final public function set_header_image( $choice ) {
 
1016
                if ( is_array( $choice ) || is_object( $choice ) ) {
 
1017
                        $choice = (array) $choice;
 
1018
                        if ( ! isset( $choice['attachment_id'] ) || ! isset( $choice['url'] ) )
 
1019
                                return;
 
1020
 
 
1021
                        $choice['url'] = esc_url_raw( $choice['url'] );
 
1022
 
 
1023
                        $header_image_data = (object) array(
 
1024
                                'attachment_id' => $choice['attachment_id'],
 
1025
                                'url'           => $choice['url'],
 
1026
                                'thumbnail_url' => $choice['url'],
 
1027
                                'height'        => $choice['height'],
 
1028
                                'width'         => $choice['width'],
 
1029
                        );
 
1030
 
 
1031
                        update_post_meta( $choice['attachment_id'], '_wp_attachment_is_custom_header', get_stylesheet() );
 
1032
                        set_theme_mod( 'header_image', $choice['url'] );
 
1033
                        set_theme_mod( 'header_image_data', $header_image_data );
 
1034
                        return;
 
1035
                }
 
1036
 
 
1037
                if ( in_array( $choice, array( 'remove-header', 'random-default-image', 'random-uploaded-image' ) ) ) {
 
1038
                        set_theme_mod( 'header_image', $choice );
 
1039
                        remove_theme_mod( 'header_image_data' );
 
1040
                        return;
 
1041
                }
 
1042
 
 
1043
                $uploaded = get_uploaded_header_images();
 
1044
                if ( $uploaded && isset( $uploaded[ $choice ] ) ) {
 
1045
                        $header_image_data = $uploaded[ $choice ];
 
1046
 
 
1047
                } else {
 
1048
                        $this->process_default_headers();
 
1049
                        if ( isset( $this->default_headers[ $choice ] ) )
 
1050
                                $header_image_data = $this->default_headers[ $choice ];
 
1051
                        else
 
1052
                                return;
 
1053
                }
 
1054
 
 
1055
                set_theme_mod( 'header_image', esc_url_raw( $header_image_data['url'] ) );
 
1056
                set_theme_mod( 'header_image_data', $header_image_data );
 
1057
        }
 
1058
 
 
1059
        /**
 
1060
         * Remove a header image.
 
1061
         *
 
1062
         * @since 3.4.0
 
1063
         */
 
1064
        final public function remove_header_image() {
 
1065
                return $this->set_header_image( 'remove-header' );
 
1066
        }
 
1067
 
 
1068
        /**
 
1069
         * Reset a header image to the default image for the theme.
 
1070
         *
 
1071
         * This method does not do anything if the theme does not have a default header image.
 
1072
         *
 
1073
         * @since 3.4.0
 
1074
         */
 
1075
        final public function reset_header_image() {
 
1076
                $this->process_default_headers();
 
1077
                $default = get_theme_support( 'custom-header', 'default-image' );
 
1078
 
 
1079
                if ( ! $default )
 
1080
                        return $this->remove_header_image();
 
1081
 
 
1082
                $default = sprintf( $default, get_template_directory_uri(), get_stylesheet_directory_uri() );
 
1083
 
 
1084
                $default_data = array();
 
1085
                foreach ( $this->default_headers as $header => $details ) {
 
1086
                        if ( $details['url'] == $default ) {
 
1087
                                $default_data = $details;
 
1088
                                break;
 
1089
                        }
 
1090
                }
 
1091
 
 
1092
                set_theme_mod( 'header_image', $default );
 
1093
                set_theme_mod( 'header_image_data', (object) $default_data );
 
1094
        }
 
1095
 
 
1096
        /**
 
1097
         * Calculate width and height based on what the currently selected theme supports.
 
1098
         *
 
1099
         * @return array dst_height and dst_width of header image.
 
1100
         */
 
1101
        final public function get_header_dimensions( $dimensions ) {
 
1102
                $max_width = 0;
 
1103
                $width = absint( $dimensions['width'] );
 
1104
                $height = absint( $dimensions['height'] );
 
1105
                $theme_height = get_theme_support( 'custom-header', 'height' );
 
1106
                $theme_width = get_theme_support( 'custom-header', 'width' );
 
1107
                $has_flex_width = current_theme_supports( 'custom-header', 'flex-width' );
 
1108
                $has_flex_height = current_theme_supports( 'custom-header', 'flex-height' );
 
1109
                $has_max_width = current_theme_supports( 'custom-header', 'max-width' ) ;
 
1110
                $dst = array( 'dst_height' => null, 'dst_height' => null );
 
1111
 
 
1112
                // For flex, limit size of image displayed to 1500px unless theme says otherwise
 
1113
                if ( $has_flex_width ) {
 
1114
                        $max_width = 1500;
 
1115
                }
 
1116
 
 
1117
                if ( $has_max_width ) {
 
1118
                        $max_width = max( $max_width, get_theme_support( 'custom-header', 'max-width' ) );
 
1119
                }
 
1120
                $max_width = max( $max_width, $theme_width );
 
1121
 
 
1122
                if ( $has_flex_height && ( ! $has_flex_width || $width > $max_width ) ) {
 
1123
                        $dst['dst_height'] = absint( $height * ( $max_width / $width ) );
 
1124
                }
 
1125
                elseif ( $has_flex_height && $has_flex_width ) {
 
1126
                        $dst['dst_height'] = $height;
 
1127
                }
 
1128
                else {
 
1129
                        $dst['dst_height'] = $theme_height;
 
1130
                }
 
1131
 
 
1132
                if ( $has_flex_width && ( ! $has_flex_height || $width > $max_width ) ) {
 
1133
                        $dst['dst_width'] = absint( $width * ( $max_width / $width ) );
 
1134
                }
 
1135
                elseif ( $has_flex_width && $has_flex_height ) {
 
1136
                        $dst['dst_width'] = $width;
 
1137
                }
 
1138
                else {
 
1139
                        $dst['dst_width'] = $theme_width;
 
1140
                }
 
1141
 
 
1142
                return $dst;
 
1143
        }
 
1144
 
 
1145
        /**
 
1146
         * Create an attachment 'object'.
 
1147
         *
 
1148
         * @param string $cropped Cropped image URL.
 
1149
         * @param int $parent_attachment_id Attachment ID of parent image.
 
1150
         *
 
1151
         * @return array Attachment object.
 
1152
         */
 
1153
        final public function create_attachment_object( $cropped, $parent_attachment_id ) {
 
1154
                $parent = get_post( $parent_attachment_id );
 
1155
                $parent_url = $parent->guid;
 
1156
                $url = str_replace( basename( $parent_url ), basename( $cropped ), $parent_url );
 
1157
 
 
1158
                $size = @getimagesize( $cropped );
 
1159
                $image_type = ( $size ) ? $size['mime'] : 'image/jpeg';
 
1160
 
 
1161
                $object = array(
 
1162
                        'ID' => $parent_attachment_id,
 
1163
                        'post_title' => basename($cropped),
 
1164
                        'post_content' => $url,
 
1165
                        'post_mime_type' => $image_type,
 
1166
                        'guid' => $url,
 
1167
                        'context' => 'custom-header'
 
1168
                );
 
1169
 
 
1170
                return $object;
 
1171
        }
 
1172
 
 
1173
        /**
 
1174
         * Insert an attachment and its metadata.
 
1175
         *
 
1176
         * @param array $object Attachment object.
 
1177
         * @param string $cropped Cropped image URL.
 
1178
         *
 
1179
         * @return int Attachment ID.
 
1180
         */
 
1181
        final public function insert_attachment( $object, $cropped ) {
 
1182
                $attachment_id = wp_insert_attachment( $object, $cropped );
 
1183
                $metadata = wp_generate_attachment_metadata( $attachment_id, $cropped );
 
1184
                /**
 
1185
                 * Filter the header image attachment metadata.
 
1186
                 *
 
1187
                 * @since 3.9.0
 
1188
                 *
 
1189
                 * @see wp_generate_attachment_metadata()
 
1190
                 *
 
1191
                 * @param array $metadata Attachment metadata.
 
1192
                 */
 
1193
                $metadata = apply_filters( 'wp_header_image_attachment_metadata', $metadata );
 
1194
                wp_update_attachment_metadata( $attachment_id, $metadata );
 
1195
                return $attachment_id;
 
1196
        }
 
1197
 
 
1198
        /**
 
1199
         * Gets attachment uploaded by Media Manager, crops it, then saves it as a
 
1200
         * new object. Returns JSON-encoded object details.
 
1201
         */
 
1202
        public function ajax_header_crop() {
 
1203
                check_ajax_referer( 'image_editor-' . $_POST['id'], 'nonce' );
 
1204
 
 
1205
                if ( ! current_user_can( 'edit_theme_options' ) ) {
 
1206
                        wp_send_json_error();
 
1207
                }
 
1208
 
 
1209
                if ( ! current_theme_supports( 'custom-header', 'uploads' ) ) {
 
1210
                        wp_send_json_error();
 
1211
                }
 
1212
 
 
1213
                $crop_details = $_POST['cropDetails'];
 
1214
 
 
1215
                $dimensions = $this->get_header_dimensions( array(
 
1216
                        'height' => $crop_details['height'],
 
1217
                        'width'  => $crop_details['width'],
 
1218
                ) );
 
1219
 
 
1220
                $attachment_id = absint( $_POST['id'] );
 
1221
 
 
1222
                $cropped = wp_crop_image(
 
1223
                        $attachment_id,
 
1224
                        (int) $crop_details['x1'],
 
1225
                        (int) $crop_details['y1'],
 
1226
                        (int) $crop_details['width'],
 
1227
                        (int) $crop_details['height'],
 
1228
                        (int) $dimensions['dst_width'],
 
1229
                        (int) $dimensions['dst_height']
 
1230
                );
 
1231
 
 
1232
                if ( ! $cropped || is_wp_error( $cropped ) ) {
 
1233
                        wp_send_json_error( array( 'message' => __( 'Image could not be processed. Please go back and try again.' ) ) );
 
1234
                }
 
1235
 
 
1236
                /** This filter is documented in wp-admin/custom-header.php */
 
1237
                $cropped = apply_filters( 'wp_create_file_in_uploads', $cropped, $attachment_id ); // For replication
 
1238
 
 
1239
                $object = $this->create_attachment_object( $cropped, $attachment_id );
 
1240
 
 
1241
                unset( $object['ID'] );
 
1242
 
 
1243
                $new_attachment_id = $this->insert_attachment( $object, $cropped );
 
1244
 
 
1245
                $object['attachment_id'] = $new_attachment_id;
 
1246
                $object['width']         = $dimensions['dst_width'];
 
1247
                $object['height']        = $dimensions['dst_height'];
 
1248
 
 
1249
                wp_send_json_success( $object );
 
1250
        }
 
1251
 
 
1252
        /**
 
1253
         * Given an attachment ID for a header image, updates its "last used"
 
1254
         * timestamp to now.
 
1255
         *
 
1256
         * Triggered when the user tries adds a new header image from the
 
1257
         * Media Manager, even if s/he doesn't save that change.
 
1258
         */
 
1259
        public function ajax_header_add() {
 
1260
                check_ajax_referer( 'header-add', 'nonce' );
 
1261
 
 
1262
                if ( ! current_user_can( 'edit_theme_options' ) ) {
 
1263
                        wp_send_json_error();
 
1264
                }
 
1265
 
 
1266
                $attachment_id = absint( $_POST['attachment_id'] );
 
1267
                if ( $attachment_id < 1 ) {
 
1268
                        wp_send_json_error();
 
1269
                }
 
1270
 
 
1271
                $key = '_wp_attachment_custom_header_last_used_' . get_stylesheet();
 
1272
                update_post_meta( $attachment_id, $key, time() );
 
1273
                update_post_meta( $attachment_id, '_wp_attachment_is_custom_header', get_stylesheet() );
 
1274
 
 
1275
                wp_send_json_success();
 
1276
        }
 
1277
 
 
1278
        /**
 
1279
         * Given an attachment ID for a header image, unsets it as a user-uploaded
 
1280
         * header image for the current theme.
 
1281
         *
 
1282
         * Triggered when the user clicks the overlay "X" button next to each image
 
1283
         * choice in the Customizer's Header tool.
 
1284
         */
 
1285
        public function ajax_header_remove() {
 
1286
                check_ajax_referer( 'header-remove', 'nonce' );
 
1287
 
 
1288
                if ( ! current_user_can( 'edit_theme_options' ) ) {
 
1289
                        wp_send_json_error();
 
1290
                }
 
1291
 
 
1292
                $attachment_id = absint( $_POST['attachment_id'] );
 
1293
                if ( $attachment_id < 1 ) {
 
1294
                        wp_send_json_error();
 
1295
                }
 
1296
 
 
1297
                $key = '_wp_attachment_custom_header_last_used_' . get_stylesheet();
 
1298
                delete_post_meta( $attachment_id, $key );
 
1299
                delete_post_meta( $attachment_id, '_wp_attachment_is_custom_header', get_stylesheet() );
 
1300
 
 
1301
                wp_send_json_success();
 
1302
        }
 
1303
 
 
1304
        public function customize_set_last_used( $wp_customize ) {
 
1305
                $data = $wp_customize->get_setting( 'header_image_data' )->post_value();
 
1306
 
 
1307
                if ( ! isset( $data['attachment_id'] ) ) {
 
1308
                        return;
 
1309
                }
 
1310
 
 
1311
                $attachment_id = $data['attachment_id'];
 
1312
                $key = '_wp_attachment_custom_header_last_used_' . get_stylesheet();
 
1313
                update_post_meta( $attachment_id, $key, time() );
 
1314
        }
 
1315
 
 
1316
        public function get_default_header_images() {
 
1317
                $this->process_default_headers();
 
1318
 
 
1319
                // Get the default image if there is one.
 
1320
                $default = get_theme_support( 'custom-header', 'default-image' );
 
1321
 
 
1322
                if ( ! $default ) { // If not,
 
1323
                        return $this->default_headers; // easy peasy.
 
1324
                }
 
1325
 
 
1326
                $default = sprintf( $default, get_template_directory_uri(), get_stylesheet_directory_uri() );
 
1327
                $already_has_default = false;
 
1328
 
 
1329
                foreach ( $this->default_headers as $k => $h ) {
 
1330
                        if ( $h['url'] === $default ) {
 
1331
                                $already_has_default = true;
 
1332
                                break;
 
1333
                        }
 
1334
                }
 
1335
 
 
1336
                if ( $already_has_default ) {
 
1337
                        return $this->default_headers;
 
1338
                }
 
1339
 
 
1340
                // If the one true image isn't included in the default set, prepend it.
 
1341
                $header_images = array();
 
1342
                $header_images['default'] = array(
 
1343
                        'url'           => $default,
 
1344
                        'thumbnail_url' => $default,
 
1345
                        'description'   => 'Default'
 
1346
                );
 
1347
 
 
1348
                // The rest of the set comes after.
 
1349
                $header_images = array_merge( $header_images, $this->default_headers );
 
1350
                return $header_images;
 
1351
        }
 
1352
 
 
1353
        public function get_uploaded_header_images() {
 
1354
                $header_images = get_uploaded_header_images();
 
1355
                $timestamp_key = '_wp_attachment_custom_header_last_used_' . get_stylesheet();
 
1356
                $alt_text_key = '_wp_attachment_image_alt';
 
1357
 
 
1358
                foreach ( $header_images as &$header_image ) {
 
1359
                        $header_meta = get_post_meta( $header_image['attachment_id'] );
 
1360
                        $header_image['timestamp'] = isset( $header_meta[ $timestamp_key ] ) ? $header_meta[ $timestamp_key ] : '';
 
1361
                        $header_image['alt_text'] = isset( $header_meta[ $alt_text_key ] ) ? $header_meta[ $alt_text_key ] : '';
 
1362
                }
 
1363
 
 
1364
                return $header_images;
 
1365
        }
 
1366
}