wp/wp-admin/custom-header.php
changeset 7 cf61fcea0001
parent 5 5e2f62d02dcd
child 9 177826044cd9
equal deleted inserted replaced
6:490d5cc509ed 7:cf61fcea0001
     8 
     8 
     9 /**
     9 /**
    10  * The custom header image class.
    10  * The custom header image class.
    11  *
    11  *
    12  * @since 2.1.0
    12  * @since 2.1.0
    13  * @package WordPress
       
    14  * @subpackage Administration
       
    15  */
    13  */
    16 class Custom_Image_Header {
    14 class Custom_Image_Header {
    17 
    15 
    18 	/**
    16 	/**
    19 	 * Callback for administration header.
    17 	 * Callback for administration header.
    20 	 *
    18 	 *
    21 	 * @var callback
    19 	 * @var callable
    22 	 * @since 2.1.0
    20 	 * @since 2.1.0
    23 	 */
    21 	 */
    24 	public $admin_header_callback;
    22 	public $admin_header_callback;
    25 
    23 
    26 	/**
    24 	/**
    27 	 * Callback for header div.
    25 	 * Callback for header div.
    28 	 *
    26 	 *
    29 	 * @var callback
    27 	 * @var callable
    30 	 * @since 3.0.0
    28 	 * @since 3.0.0
    31 	 */
    29 	 */
    32 	public $admin_image_div_callback;
    30 	public $admin_image_div_callback;
    33 
    31 
    34 	/**
    32 	/**
    35 	 * Holds default headers.
    33 	 * Holds default headers.
    36 	 *
    34 	 *
    37 	 * @var array
    35 	 * @var array
    38 	 * @since 3.0.0
    36 	 * @since 3.0.0
    39 	 * @access private
       
    40 	 */
    37 	 */
    41 	public $default_headers = array();
    38 	public $default_headers = array();
    42 
    39 
    43 	/**
    40 	/**
       
    41 	 * Used to trigger a success message when settings updated and set to true.
       
    42 	 *
       
    43 	 * @since 3.0.0
    44 	 * @var bool
    44 	 * @var bool
    45 	 */
    45 	 */
    46 	private $updated;
    46 	private $updated;
    47 
    47 
    48 	/**
    48 	/**
    49 	 * Constructor - Register administration header callback.
    49 	 * Constructor - Register administration header callback.
    50 	 *
    50 	 *
    51 	 * @since 2.1.0
    51 	 * @since 2.1.0
    52 	 * @param callback $admin_header_callback
    52 	 * @param callable $admin_header_callback
    53 	 * @param callback $admin_image_div_callback Optional custom image div output callback.
    53 	 * @param callable $admin_image_div_callback Optional custom image div output callback.
    54 	 */
    54 	 */
    55 	public function __construct($admin_header_callback, $admin_image_div_callback = '') {
    55 	public function __construct($admin_header_callback, $admin_image_div_callback = '') {
    56 		$this->admin_header_callback = $admin_header_callback;
    56 		$this->admin_header_callback = $admin_header_callback;
    57 		$this->admin_image_div_callback = $admin_image_div_callback;
    57 		$this->admin_image_div_callback = $admin_image_div_callback;
    58 
    58 
   118 				'<p>' . __( 'Don&#8217;t forget to click &#8220;Save Changes&#8221; when you&#8217;re done!') . '</p>'
   118 				'<p>' . __( 'Don&#8217;t forget to click &#8220;Save Changes&#8221; when you&#8217;re done!') . '</p>'
   119 		) );
   119 		) );
   120 
   120 
   121 		get_current_screen()->set_help_sidebar(
   121 		get_current_screen()->set_help_sidebar(
   122 			'<p><strong>' . __( 'For more information:' ) . '</strong></p>' .
   122 			'<p><strong>' . __( 'For more information:' ) . '</strong></p>' .
   123 			'<p>' . __( '<a href="https://codex.wordpress.org/Appearance_Header_Screen" target="_blank">Documentation on Custom Header</a>' ) . '</p>' .
   123 			'<p>' . __( '<a href="https://codex.wordpress.org/Appearance_Header_Screen">Documentation on Custom Header</a>' ) . '</p>' .
   124 			'<p>' . __( '<a href="https://wordpress.org/support/" target="_blank">Support Forums</a>' ) . '</p>'
   124 			'<p>' . __( '<a href="https://wordpress.org/support/">Support Forums</a>' ) . '</p>'
   125 		);
   125 		);
   126 	}
   126 	}
   127 
   127 
   128 	/**
   128 	/**
   129 	 * Get the current step.
   129 	 * Get the current step.
   226 
   226 
   227 	/**
   227 	/**
   228 	 * Process the default headers
   228 	 * Process the default headers
   229 	 *
   229 	 *
   230 	 * @since 3.0.0
   230 	 * @since 3.0.0
       
   231 	 *
       
   232 	 * @global array $_wp_default_headers
   231 	 */
   233 	 */
   232 	public function process_default_headers() {
   234 	public function process_default_headers() {
   233 		global $_wp_default_headers;
   235 		global $_wp_default_headers;
   234 
   236 
   235 		if ( !isset($_wp_default_headers) )
   237 		if ( !isset($_wp_default_headers) )
   253 	 *
   255 	 *
   254 	 * Show the random image option if this theme has multiple header images.
   256 	 * Show the random image option if this theme has multiple header images.
   255 	 * Random image option is on by default if no header has been set.
   257 	 * Random image option is on by default if no header has been set.
   256 	 *
   258 	 *
   257 	 * @since 3.0.0
   259 	 * @since 3.0.0
       
   260 	 *
       
   261 	 * @param string $type The header type. One of 'default' (for the Uploaded Images control)
       
   262 	 *                     or 'uploaded' (for the Uploaded Images control).
   258 	 */
   263 	 */
   259 	public function show_header_selector( $type = 'default' ) {
   264 	public function show_header_selector( $type = 'default' ) {
   260 		if ( 'default' == $type ) {
   265 		if ( 'default' == $type ) {
   261 			$headers = $this->default_headers;
   266 			$headers = $this->default_headers;
   262 		} else {
   267 		} else {
   265 		}
   270 		}
   266 
   271 
   267 		if ( 1 < count( $headers ) ) {
   272 		if ( 1 < count( $headers ) ) {
   268 			echo '<div class="random-header">';
   273 			echo '<div class="random-header">';
   269 			echo '<label><input name="default-header" type="radio" value="random-' . $type . '-image"' . checked( is_random_header_image( $type ), true, false ) . ' />';
   274 			echo '<label><input name="default-header" type="radio" value="random-' . $type . '-image"' . checked( is_random_header_image( $type ), true, false ) . ' />';
   270 			echo __( '<strong>Random:</strong> Show a different image on each page.' );
   275 			_e( '<strong>Random:</strong> Show a different image on each page.' );
   271 			echo '</label>';
   276 			echo '</label>';
   272 			echo '</div>';
   277 			echo '</div>';
   273 		}
   278 		}
   274 
   279 
   275 		echo '<div class="available-headers">';
   280 		echo '<div class="available-headers">';
   276 		foreach ( $headers as $header_key => $header ) {
   281 		foreach ( $headers as $header_key => $header ) {
   277 			$header_thumbnail = $header['thumbnail_url'];
   282 			$header_thumbnail = $header['thumbnail_url'];
   278 			$header_url = $header['url'];
   283 			$header_url = $header['url'];
   279 			$header_desc = empty( $header['description'] ) ? '' : $header['description'];
   284 			$header_alt_text = empty( $header['alt_text'] ) ? '' : $header['alt_text'];
   280 			echo '<div class="default-header">';
   285 			echo '<div class="default-header">';
   281 			echo '<label><input name="default-header" type="radio" value="' . esc_attr( $header_key ) . '" ' . checked( $header_url, get_theme_mod( 'header_image' ), false ) . ' />';
   286 			echo '<label><input name="default-header" type="radio" value="' . esc_attr( $header_key ) . '" ' . checked( $header_url, get_theme_mod( 'header_image' ), false ) . ' />';
   282 			$width = '';
   287 			$width = '';
   283 			if ( !empty( $header['attachment_id'] ) )
   288 			if ( !empty( $header['attachment_id'] ) )
   284 				$width = ' width="230"';
   289 				$width = ' width="230"';
   285 			echo '<img src="' . set_url_scheme( $header_thumbnail ) . '" alt="' . esc_attr( $header_desc ) .'" title="' . esc_attr( $header_desc ) . '"' . $width . ' /></label>';
   290 			echo '<img src="' . set_url_scheme( $header_thumbnail ) . '" alt="' . esc_attr( $header_alt_text ) .'"' . $width . ' /></label>';
   286 			echo '</div>';
   291 			echo '</div>';
   287 		}
   292 		}
   288 		echo '<div class="clear"></div></div>';
   293 		echo '<div class="clear"></div></div>';
   289 	}
   294 	}
   290 
   295 
   313 			if ( $default_color && false === strpos( $default_color, '#' ) ) {
   318 			if ( $default_color && false === strpos( $default_color, '#' ) ) {
   314 				$default_color = '#' . $default_color;
   319 				$default_color = '#' . $default_color;
   315 			}
   320 			}
   316 		}
   321 		}
   317 		?>
   322 		?>
   318 
       
   319 <script type="text/javascript">
   323 <script type="text/javascript">
   320 (function($){
   324 (function($){
   321 	var default_color = '<?php echo $default_color; ?>',
   325 	var default_color = '<?php echo $default_color; ?>',
   322 		header_text_fields;
   326 		header_text_fields;
   323 
   327 
   443 	public function step_1() {
   447 	public function step_1() {
   444 		$this->process_default_headers();
   448 		$this->process_default_headers();
   445 ?>
   449 ?>
   446 
   450 
   447 <div class="wrap">
   451 <div class="wrap">
   448 <h2><?php _e( 'Custom Header' ); ?></h2>
   452 <h1><?php _e( 'Custom Header' ); ?></h1>
   449 
   453 
   450 <?php if ( current_user_can( 'customize' ) ) { ?>
   454 <?php if ( current_user_can( 'customize' ) ) { ?>
   451 <div class="notice notice-info hide-if-no-customize">
   455 <div class="notice notice-info hide-if-no-customize">
   452 	<p>
   456 	<p>
   453 		<?php
   457 		<?php
   506 	<?php } ?>
   510 	<?php } ?>
   507 </td>
   511 </td>
   508 </tr>
   512 </tr>
   509 <?php endif; ?>
   513 <?php endif; ?>
   510 
   514 
   511 <?php if ( current_theme_supports( 'custom-header', 'uploads' ) ) : ?>
   515 <?php if ( current_user_can( 'upload_files' ) && current_theme_supports( 'custom-header', 'uploads' ) ) : ?>
   512 <tr>
   516 <tr>
   513 <th scope="row"><?php _e( 'Select Image' ); ?></th>
   517 <th scope="row"><?php _e( 'Select Image' ); ?></th>
   514 <td>
   518 <td>
   515 	<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 />
   519 	<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 />
   516 	<?php
   520 	<?php
   517 	if ( ! current_theme_supports( 'custom-header', 'flex-height' ) && ! current_theme_supports( 'custom-header', 'flex-width' ) ) {
   521 	if ( ! current_theme_supports( 'custom-header', 'flex-height' ) && ! current_theme_supports( 'custom-header', 'flex-width' ) ) {
   518 		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' ) );
   522 		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' ) );
   519 	} elseif ( current_theme_supports( 'custom-header', 'flex-height' ) ) {
   523 	} elseif ( current_theme_supports( 'custom-header', 'flex-height' ) ) {
   520 		if ( ! current_theme_supports( 'custom-header', 'flex-width' ) )
   524 		if ( ! current_theme_supports( 'custom-header', 'flex-width' ) )
   521 			printf( __( 'Images should be at least <strong>%1$d pixels</strong> wide.' ) . ' ', get_theme_support( 'custom-header', 'width' ) );
   525 			printf(
       
   526 				/* translators: %s: size in pixels */
       
   527 				__( 'Images should be at least %s wide.' ) . ' ',
       
   528 				sprintf(
       
   529 					/* translators: %d: custom header width */
       
   530 					'<strong>' . __( '%d pixels' ) . '</strong>',
       
   531 					get_theme_support( 'custom-header', 'width' )
       
   532 				)
       
   533 			);
   522 	} elseif ( current_theme_supports( 'custom-header', 'flex-width' ) ) {
   534 	} elseif ( current_theme_supports( 'custom-header', 'flex-width' ) ) {
   523 		if ( ! current_theme_supports( 'custom-header', 'flex-height' ) )
   535 		if ( ! current_theme_supports( 'custom-header', 'flex-height' ) )
   524 			printf( __( 'Images should be at least <strong>%1$d pixels</strong> tall.' ) . ' ', get_theme_support( 'custom-header', 'height' ) );
   536 			printf(
       
   537 				/* translators: %s: size in pixels */
       
   538 				__( 'Images should be at least %s tall.' ) . ' ',
       
   539 				sprintf(
       
   540 					/* translators: %d: custom header height */
       
   541 					'<strong>' . __( '%d pixels' ) . '</strong>',
       
   542 					get_theme_support( 'custom-header', 'height' )
       
   543 				)
       
   544 			);
   525 	}
   545 	}
   526 	if ( current_theme_supports( 'custom-header', 'flex-height' ) || current_theme_supports( 'custom-header', 'flex-width' ) ) {
   546 	if ( current_theme_supports( 'custom-header', 'flex-height' ) || current_theme_supports( 'custom-header', 'flex-width' ) ) {
   527 		if ( current_theme_supports( 'custom-header', 'width' ) )
   547 		if ( current_theme_supports( 'custom-header', 'width' ) )
   528 			printf( __( 'Suggested width is <strong>%1$d pixels</strong>.' ) . ' ', get_theme_support( 'custom-header', 'width' ) );
   548 			printf(
       
   549 				/* translators: %s: size in pixels */
       
   550 				__( 'Suggested width is %s.' ) . ' ',
       
   551 				sprintf(
       
   552 					/* translators: %d: custom header width */
       
   553 					'<strong>' . __( '%d pixels' ) . '</strong>',
       
   554 					get_theme_support( 'custom-header', 'width' )
       
   555 				)
       
   556 			);
   529 		if ( current_theme_supports( 'custom-header', 'height' ) )
   557 		if ( current_theme_supports( 'custom-header', 'height' ) )
   530 			printf( __( 'Suggested height is <strong>%1$d pixels</strong>.' ) . ' ', get_theme_support( 'custom-header', 'height' ) );
   558 			printf(
       
   559 				/* translators: %s: size in pixels */
       
   560 				__( 'Suggested height is %s.' ) . ' ',
       
   561 				sprintf(
       
   562 					/* translators: %d: custom header height */
       
   563 					'<strong>' . __( '%d pixels' ) . '</strong>',
       
   564 					get_theme_support( 'custom-header', 'height' )
       
   565 				)
       
   566 			);
   531 	}
   567 	}
   532 	?></p>
   568 	?></p>
   533 	<form enctype="multipart/form-data" id="upload-form" class="wp-upload-form" method="post" action="<?php echo esc_url( add_query_arg( 'step', 2 ) ) ?>">
   569 	<form enctype="multipart/form-data" id="upload-form" class="wp-upload-form" method="post" action="<?php echo esc_url( add_query_arg( 'step', 2 ) ) ?>">
   534 	<p>
   570 	<p>
   535 		<label for="upload"><?php _e( 'Choose an image from your computer:' ); ?></label><br />
   571 		<label for="upload"><?php _e( 'Choose an image from your computer:' ); ?></label><br />
   536 		<input type="file" id="upload" name="import" />
   572 		<input type="file" id="upload" name="import" />
   537 		<input type="hidden" name="action" value="save" />
   573 		<input type="hidden" name="action" value="save" />
   538 		<?php wp_nonce_field( 'custom-header-upload', '_wpnonce-custom-header-upload' ); ?>
   574 		<?php wp_nonce_field( 'custom-header-upload', '_wpnonce-custom-header-upload' ); ?>
   539 		<?php submit_button( __( 'Upload' ), 'button', 'submit', false ); ?>
   575 		<?php submit_button( __( 'Upload' ), '', 'submit', false ); ?>
   540 	</p>
   576 	</p>
   541 	<?php
   577 	<?php
   542 		$modal_update_href = esc_url( add_query_arg( array(
   578 		$modal_update_href = esc_url( add_query_arg( array(
   543 			'page' => 'custom-header',
   579 			'page' => 'custom-header',
   544 			'step' => 2,
   580 			'step' => 2,
   592 	if ( get_header_image() ) : ?>
   628 	if ( get_header_image() ) : ?>
   593 <tr>
   629 <tr>
   594 <th scope="row"><?php _e( 'Remove Image' ); ?></th>
   630 <th scope="row"><?php _e( 'Remove Image' ); ?></th>
   595 <td>
   631 <td>
   596 	<p><?php _e( 'This will remove the header image. You will not be able to restore any customizations.' ) ?></p>
   632 	<p><?php _e( 'This will remove the header image. You will not be able to restore any customizations.' ) ?></p>
   597 	<?php submit_button( __( 'Remove Header Image' ), 'button', 'removeheader', false ); ?>
   633 	<?php submit_button( __( 'Remove Header Image' ), '', 'removeheader', false ); ?>
   598 </td>
   634 </td>
   599 </tr>
   635 </tr>
   600 	<?php endif;
   636 	<?php endif;
   601 
   637 
   602 	$default_image = get_theme_support( 'custom-header', 'default-image' );
   638 	$default_image = sprintf( get_theme_support( 'custom-header', 'default-image' ), get_template_directory_uri(), get_stylesheet_directory_uri() );
   603 	if ( $default_image && get_header_image() != $default_image ) : ?>
   639 	if ( $default_image && get_header_image() != $default_image ) : ?>
   604 <tr>
   640 <tr>
   605 <th scope="row"><?php _e( 'Reset Image' ); ?></th>
   641 <th scope="row"><?php _e( 'Reset Image' ); ?></th>
   606 <td>
   642 <td>
   607 	<p><?php _e( 'This will restore the original header image. You will not be able to restore any customizations.' ) ?></p>
   643 	<p><?php _e( 'This will restore the original header image. You will not be able to restore any customizations.' ) ?></p>
   608 	<?php submit_button( __( 'Restore Original Header Image' ), 'button', 'resetheader', false ); ?>
   644 	<?php submit_button( __( 'Restore Original Header Image' ), '', 'resetheader', false ); ?>
   609 </td>
   645 </td>
   610 </tr>
   646 </tr>
   611 	<?php endif; ?>
   647 	<?php endif; ?>
   612 </tbody>
   648 </tbody>
   613 </table>
   649 </table>
   679 	 *
   715 	 *
   680 	 * @since 2.1.0
   716 	 * @since 2.1.0
   681 	 */
   717 	 */
   682 	public function step_2() {
   718 	public function step_2() {
   683 		check_admin_referer('custom-header-upload', '_wpnonce-custom-header-upload');
   719 		check_admin_referer('custom-header-upload', '_wpnonce-custom-header-upload');
   684 		if ( ! current_theme_supports( 'custom-header', 'uploads' ) )
   720 		if ( ! current_theme_supports( 'custom-header', 'uploads' ) ) {
   685 			wp_die( __( 'Cheatin&#8217; uh?' ), 403 );
   721 			wp_die(
       
   722 				'<h1>' . __( 'Something went wrong.' ) . '</h1>' .
       
   723 				'<p>' . __( 'The current theme does not support uploading a custom header image.' ) . '</p>',
       
   724 				403
       
   725 			);
       
   726 		}
   686 
   727 
   687 		if ( empty( $_POST ) && isset( $_GET['file'] ) ) {
   728 		if ( empty( $_POST ) && isset( $_GET['file'] ) ) {
   688 			$attachment_id = absint( $_GET['file'] );
   729 			$attachment_id = absint( $_GET['file'] );
   689 			$file = get_attached_file( $attachment_id, true );
   730 			$file = get_attached_file( $attachment_id, true );
   690 			$url = wp_get_attachment_image_src( $attachment_id, 'full' );
   731 			$url = wp_get_attachment_image_src( $attachment_id, 'full' );
   751 			$oitar = 1;
   792 			$oitar = 1;
   752 		}
   793 		}
   753 		?>
   794 		?>
   754 
   795 
   755 <div class="wrap">
   796 <div class="wrap">
   756 <h2><?php _e( 'Crop Header Image' ); ?></h2>
   797 <h1><?php _e( 'Crop Header Image' ); ?></h1>
   757 
   798 
   758 <form method="post" action="<?php echo esc_url(add_query_arg('step', 3)); ?>">
   799 <form method="post" action="<?php echo esc_url(add_query_arg('step', 3)); ?>">
   759 	<p class="hide-if-no-js"><?php _e('Choose the part of the image you want to use as your header.'); ?></p>
   800 	<p class="hide-if-no-js"><?php _e('Choose the part of the image you want to use as your header.'); ?></p>
   760 	<p class="hide-if-js"><strong><?php _e( 'You need Javascript to choose a part of the image.'); ?></strong></p>
   801 	<p class="hide-if-js"><strong><?php _e( 'You need JavaScript to choose a part of the image.'); ?></strong></p>
   761 
   802 
   762 	<div id="crop_image" style="position: relative">
   803 	<div id="crop_image" style="position: relative">
   763 		<img src="<?php echo esc_url( $url ); ?>" id="upload" width="<?php echo $width; ?>" height="<?php echo $height; ?>" />
   804 		<img src="<?php echo esc_url( $url ); ?>" id="upload" width="<?php echo $width; ?>" height="<?php echo $height; ?>" alt="" />
   764 	</div>
   805 	</div>
   765 
   806 
   766 	<input type="hidden" name="x1" id="x1" value="0"/>
   807 	<input type="hidden" name="x1" id="x1" value="0"/>
   767 	<input type="hidden" name="y1" id="y1" value="0"/>
   808 	<input type="hidden" name="y1" id="y1" value="0"/>
   768 	<input type="hidden" name="width" id="width" value="<?php echo esc_attr( $width ); ?>"/>
   809 	<input type="hidden" name="width" id="width" value="<?php echo esc_attr( $width ); ?>"/>
   776 
   817 
   777 	<p class="submit">
   818 	<p class="submit">
   778 	<?php submit_button( __( 'Crop and Publish' ), 'primary', 'submit', false ); ?>
   819 	<?php submit_button( __( 'Crop and Publish' ), 'primary', 'submit', false ); ?>
   779 	<?php
   820 	<?php
   780 	if ( isset( $oitar ) && 1 == $oitar && ( current_theme_supports( 'custom-header', 'flex-height' ) || current_theme_supports( 'custom-header', 'flex-width' ) ) )
   821 	if ( isset( $oitar ) && 1 == $oitar && ( current_theme_supports( 'custom-header', 'flex-height' ) || current_theme_supports( 'custom-header', 'flex-width' ) ) )
   781 		submit_button( __( 'Skip Cropping, Publish Image as Is' ), 'secondary', 'skip-cropping', false );
   822 		submit_button( __( 'Skip Cropping, Publish Image as Is' ), '', 'skip-cropping', false );
   782 	?>
   823 	?>
   783 	</p>
   824 	</p>
   784 </form>
   825 </form>
   785 </div>
   826 </div>
   786 		<?php
   827 		<?php
   826 
   867 
   827 	/**
   868 	/**
   828 	 * Display third step of custom header image page.
   869 	 * Display third step of custom header image page.
   829 	 *
   870 	 *
   830 	 * @since 2.1.0
   871 	 * @since 2.1.0
       
   872 	 * @since 4.4.0 Switched to using wp_get_attachment_url() instead of the guid
       
   873 	 *              for retrieving the header image URL.
   831 	 */
   874 	 */
   832 	public function step_3() {
   875 	public function step_3() {
   833 		check_admin_referer( 'custom-header-crop-image' );
   876 		check_admin_referer( 'custom-header-crop-image' );
   834 
   877 
   835 		if ( ! current_theme_supports( 'custom-header', 'uploads' ) )
   878 		if ( ! current_theme_supports( 'custom-header', 'uploads' ) ) {
   836 			wp_die( __( 'Cheatin&#8217; uh?' ), 403 );
   879 			wp_die(
   837 
   880 				'<h1>' . __( 'Something went wrong.' ) . '</h1>' .
   838 		if ( ! empty( $_POST['skip-cropping'] ) && ! ( current_theme_supports( 'custom-header', 'flex-height' ) || current_theme_supports( 'custom-header', 'flex-width' ) ) )
   881 				'<p>' . __( 'The current theme does not support uploading a custom header image.' ) . '</p>',
   839 			wp_die( __( 'Cheatin&#8217; uh?' ), 403 );
   882 				403
       
   883 			);
       
   884 		}
       
   885 
       
   886 		if ( ! empty( $_POST['skip-cropping'] ) && ! ( current_theme_supports( 'custom-header', 'flex-height' ) || current_theme_supports( 'custom-header', 'flex-width' ) ) ) {
       
   887 			wp_die(
       
   888 				'<h1>' . __( 'Something went wrong.' ) . '</h1>' .
       
   889 				'<p>' . __( 'The current theme does not support a flexible sized header image.' ) . '</p>',
       
   890 				403
       
   891 			);
       
   892 		}
   840 
   893 
   841 		if ( $_POST['oitar'] > 1 ) {
   894 		if ( $_POST['oitar'] > 1 ) {
   842 			$_POST['x1'] = $_POST['x1'] * $_POST['oitar'];
   895 			$_POST['x1'] = $_POST['x1'] * $_POST['oitar'];
   843 			$_POST['y1'] = $_POST['y1'] * $_POST['oitar'];
   896 			$_POST['y1'] = $_POST['y1'] * $_POST['oitar'];
   844 			$_POST['width'] = $_POST['width'] * $_POST['oitar'];
   897 			$_POST['width'] = $_POST['width'] * $_POST['oitar'];
   874 			unset( $object['ID'] );
   927 			unset( $object['ID'] );
   875 
   928 
   876 		// Update the attachment
   929 		// Update the attachment
   877 		$attachment_id = $this->insert_attachment( $object, $cropped );
   930 		$attachment_id = $this->insert_attachment( $object, $cropped );
   878 
   931 
   879 		$url = $object['guid'];
   932 		$url = wp_get_attachment_url( $attachment_id );
   880 		$this->set_header_image( compact( 'url', 'attachment_id', 'width', 'height' ) );
   933 		$this->set_header_image( compact( 'url', 'attachment_id', 'width', 'height' ) );
   881 
   934 
   882 		// Cleanup.
   935 		// Cleanup.
   883 		$medium = str_replace( basename( $original ), 'midsize-' . basename( $original ), $original );
   936 		$medium = str_replace( basename( $original ), 'midsize-' . basename( $original ), $original );
   884 		if ( file_exists( $medium ) ) {
   937 		if ( file_exists( $medium ) ) {
   907 	 *
   960 	 *
   908 	 * @since 2.1.0
   961 	 * @since 2.1.0
   909 	 */
   962 	 */
   910 	public function admin_page() {
   963 	public function admin_page() {
   911 		if ( ! current_user_can('edit_theme_options') )
   964 		if ( ! current_user_can('edit_theme_options') )
   912 			wp_die(__('You do not have permission to customize headers.'));
   965 			wp_die(__('Sorry, you are not allowed to customize headers.'));
   913 		$step = $this->step();
   966 		$step = $this->step();
   914 		if ( 2 == $step )
   967 		if ( 2 == $step )
   915 			$this->step_2();
   968 			$this->step_2();
   916 		elseif ( 3 == $step )
   969 		elseif ( 3 == $step )
   917 			$this->step_3();
   970 			$this->step_3();
   921 
   974 
   922 	/**
   975 	/**
   923 	 * Unused since 3.5.0.
   976 	 * Unused since 3.5.0.
   924 	 *
   977 	 *
   925 	 * @since 3.4.0
   978 	 * @since 3.4.0
       
   979 	 *
       
   980 	 * @param array $form_fields
       
   981 	 * @return array $form_fields
   926 	 */
   982 	 */
   927 	public function attachment_fields_to_edit( $form_fields ) {
   983 	public function attachment_fields_to_edit( $form_fields ) {
   928 		return $form_fields;
   984 		return $form_fields;
   929 	}
   985 	}
   930 
   986 
   931 	/**
   987 	/**
   932 	 * Unused since 3.5.0.
   988 	 * Unused since 3.5.0.
   933 	 *
   989 	 *
   934 	 * @since 3.4.0
   990 	 * @since 3.4.0
       
   991 	 *
       
   992 	 * @param array $tabs
       
   993 	 * @return array $tabs
   935 	 */
   994 	 */
   936 	public function filter_upload_tabs( $tabs ) {
   995 	public function filter_upload_tabs( $tabs ) {
   937 		return $tabs;
   996 		return $tabs;
   938 	}
   997 	}
   939 
   998 
   940 	/**
   999 	/**
   941 	 * Choose a header image, selected from existing uploaded and default headers,
  1000 	 * Choose a header image, selected from existing uploaded and default headers,
   942 	 * or provide an array of uploaded header data (either new, or from media library).
  1001 	 * or provide an array of uploaded header data (either new, or from media library).
       
  1002 	 *
       
  1003 	 * @since 3.4.0
   943 	 *
  1004 	 *
   944 	 * @param mixed $choice Which header image to select. Allows for values of 'random-default-image',
  1005 	 * @param mixed $choice Which header image to select. Allows for values of 'random-default-image',
   945 	 * 	for randomly cycling among the default images; 'random-uploaded-image', for randomly cycling
  1006 	 * 	for randomly cycling among the default images; 'random-uploaded-image', for randomly cycling
   946 	 * 	among the uploaded images; the key of a default image registered for that theme; and
  1007 	 * 	among the uploaded images; the key of a default image registered for that theme; and
   947 	 * 	the key of an image uploaded for that theme (the basename of the URL).
  1008 	 * 	the key of an image uploaded for that theme (the attachment ID of the image).
   948 	 *  Or an array of arguments: attachment_id, url, width, height. All are required.
  1009 	 *  Or an array of arguments: attachment_id, url, width, height. All are required.
   949 	 *
       
   950 	 * @since 3.4.0
       
   951 	 */
  1010 	 */
   952 	final public function set_header_image( $choice ) {
  1011 	final public function set_header_image( $choice ) {
   953 		if ( is_array( $choice ) || is_object( $choice ) ) {
  1012 		if ( is_array( $choice ) || is_object( $choice ) ) {
   954 			$choice = (array) $choice;
  1013 			$choice = (array) $choice;
   955 			if ( ! isset( $choice['attachment_id'] ) || ! isset( $choice['url'] ) )
  1014 			if ( ! isset( $choice['attachment_id'] ) || ! isset( $choice['url'] ) )
   997 	 * Remove a header image.
  1056 	 * Remove a header image.
   998 	 *
  1057 	 *
   999 	 * @since 3.4.0
  1058 	 * @since 3.4.0
  1000 	 */
  1059 	 */
  1001 	final public function remove_header_image() {
  1060 	final public function remove_header_image() {
  1002 		return $this->set_header_image( 'remove-header' );
  1061 		$this->set_header_image( 'remove-header' );
  1003 	}
  1062 	}
  1004 
  1063 
  1005 	/**
  1064 	/**
  1006 	 * Reset a header image to the default image for the theme.
  1065 	 * Reset a header image to the default image for the theme.
  1007 	 *
  1066 	 *
  1011 	 */
  1070 	 */
  1012 	final public function reset_header_image() {
  1071 	final public function reset_header_image() {
  1013 		$this->process_default_headers();
  1072 		$this->process_default_headers();
  1014 		$default = get_theme_support( 'custom-header', 'default-image' );
  1073 		$default = get_theme_support( 'custom-header', 'default-image' );
  1015 
  1074 
  1016 		if ( ! $default )
  1075 		if ( ! $default ) {
  1017 			return $this->remove_header_image();
  1076 			$this->remove_header_image();
  1018 
  1077 			return;
       
  1078 		}
  1019 		$default = sprintf( $default, get_template_directory_uri(), get_stylesheet_directory_uri() );
  1079 		$default = sprintf( $default, get_template_directory_uri(), get_stylesheet_directory_uri() );
  1020 
  1080 
  1021 		$default_data = array();
  1081 		$default_data = array();
  1022 		foreach ( $this->default_headers as $header => $details ) {
  1082 		foreach ( $this->default_headers as $header => $details ) {
  1023 			if ( $details['url'] == $default ) {
  1083 			if ( $details['url'] == $default ) {
  1031 	}
  1091 	}
  1032 
  1092 
  1033 	/**
  1093 	/**
  1034 	 * Calculate width and height based on what the currently selected theme supports.
  1094 	 * Calculate width and height based on what the currently selected theme supports.
  1035 	 *
  1095 	 *
       
  1096 	 * @since 3.9.0
       
  1097 	 *
       
  1098 	 * @param array $dimensions
  1036 	 * @return array dst_height and dst_width of header image.
  1099 	 * @return array dst_height and dst_width of header image.
  1037 	 */
  1100 	 */
  1038 	final public function get_header_dimensions( $dimensions ) {
  1101 	final public function get_header_dimensions( $dimensions ) {
  1039 		$max_width = 0;
  1102 		$max_width = 0;
  1040 		$width = absint( $dimensions['width'] );
  1103 		$width = absint( $dimensions['width'] );
  1080 	}
  1143 	}
  1081 
  1144 
  1082 	/**
  1145 	/**
  1083 	 * Create an attachment 'object'.
  1146 	 * Create an attachment 'object'.
  1084 	 *
  1147 	 *
  1085 	 * @param string $cropped Cropped image URL.
  1148 	 * @since 3.9.0
  1086 	 * @param int $parent_attachment_id Attachment ID of parent image.
  1149 	 *
  1087 	 *
  1150 	 * @param string $cropped              Cropped image URL.
       
  1151 	 * @param int    $parent_attachment_id Attachment ID of parent image.
  1088 	 * @return array Attachment object.
  1152 	 * @return array Attachment object.
  1089 	 */
  1153 	 */
  1090 	final public function create_attachment_object( $cropped, $parent_attachment_id ) {
  1154 	final public function create_attachment_object( $cropped, $parent_attachment_id ) {
  1091 		$parent = get_post( $parent_attachment_id );
  1155 		$parent = get_post( $parent_attachment_id );
  1092 		$parent_url = $parent->guid;
  1156 		$parent_url = wp_get_attachment_url( $parent->ID );
  1093 		$url = str_replace( basename( $parent_url ), basename( $cropped ), $parent_url );
  1157 		$url = str_replace( basename( $parent_url ), basename( $cropped ), $parent_url );
  1094 
  1158 
  1095 		$size = @getimagesize( $cropped );
  1159 		$size = @getimagesize( $cropped );
  1096 		$image_type = ( $size ) ? $size['mime'] : 'image/jpeg';
  1160 		$image_type = ( $size ) ? $size['mime'] : 'image/jpeg';
  1097 
  1161 
  1098 		$object = array(
  1162 		$object = array(
  1099 			'ID' => $parent_attachment_id,
  1163 			'ID' => $parent_attachment_id,
  1100 			'post_title' => basename($cropped),
  1164 			'post_title' => basename($cropped),
  1101 			'post_content' => $url,
       
  1102 			'post_mime_type' => $image_type,
  1165 			'post_mime_type' => $image_type,
  1103 			'guid' => $url,
  1166 			'guid' => $url,
  1104 			'context' => 'custom-header'
  1167 			'context' => 'custom-header',
       
  1168 			'post_parent' => $parent_attachment_id,
  1105 		);
  1169 		);
  1106 
  1170 
  1107 		return $object;
  1171 		return $object;
  1108 	}
  1172 	}
  1109 
  1173 
  1110 	/**
  1174 	/**
  1111 	 * Insert an attachment and its metadata.
  1175 	 * Insert an attachment and its metadata.
  1112 	 *
  1176 	 *
  1113 	 * @param array $object Attachment object.
  1177 	 * @since 3.9.0
       
  1178 	 *
       
  1179 	 * @param array  $object  Attachment object.
  1114 	 * @param string $cropped Cropped image URL.
  1180 	 * @param string $cropped Cropped image URL.
  1115 	 *
       
  1116 	 * @return int Attachment ID.
  1181 	 * @return int Attachment ID.
  1117 	 */
  1182 	 */
  1118 	final public function insert_attachment( $object, $cropped ) {
  1183 	final public function insert_attachment( $object, $cropped ) {
       
  1184 		$parent_id = isset( $object['post_parent'] ) ? $object['post_parent'] : null;
       
  1185 		unset( $object['post_parent'] );
       
  1186 
  1119 		$attachment_id = wp_insert_attachment( $object, $cropped );
  1187 		$attachment_id = wp_insert_attachment( $object, $cropped );
  1120 		$metadata = wp_generate_attachment_metadata( $attachment_id, $cropped );
  1188 		$metadata = wp_generate_attachment_metadata( $attachment_id, $cropped );
       
  1189 
       
  1190 		// If this is a crop, save the original attachment ID as metadata.
       
  1191 		if ( $parent_id ) {
       
  1192 			$metadata['attachment_parent'] = $parent_id;
       
  1193 		}
       
  1194 
  1121 		/**
  1195 		/**
  1122 		 * Filter the header image attachment metadata.
  1196 		 * Filters the header image attachment metadata.
  1123 		 *
  1197 		 *
  1124 		 * @since 3.9.0
  1198 		 * @since 3.9.0
  1125 		 *
  1199 		 *
  1126 		 * @see wp_generate_attachment_metadata()
  1200 		 * @see wp_generate_attachment_metadata()
  1127 		 *
  1201 		 *
  1128 		 * @param array $metadata Attachment metadata.
  1202 		 * @param array $metadata Attachment metadata.
  1129 		 */
  1203 		 */
  1130 		$metadata = apply_filters( 'wp_header_image_attachment_metadata', $metadata );
  1204 		$metadata = apply_filters( 'wp_header_image_attachment_metadata', $metadata );
       
  1205 
  1131 		wp_update_attachment_metadata( $attachment_id, $metadata );
  1206 		wp_update_attachment_metadata( $attachment_id, $metadata );
       
  1207 
  1132 		return $attachment_id;
  1208 		return $attachment_id;
  1133 	}
  1209 	}
  1134 
  1210 
  1135 	/**
  1211 	/**
  1136 	 * Gets attachment uploaded by Media Manager, crops it, then saves it as a
  1212 	 * Gets attachment uploaded by Media Manager, crops it, then saves it as a
  1137 	 * new object. Returns JSON-encoded object details.
  1213 	 * new object. Returns JSON-encoded object details.
       
  1214 	 *
       
  1215 	 * @since 3.9.0
  1138 	 */
  1216 	 */
  1139 	public function ajax_header_crop() {
  1217 	public function ajax_header_crop() {
  1140 		check_ajax_referer( 'image_editor-' . $_POST['id'], 'nonce' );
  1218 		check_ajax_referer( 'image_editor-' . $_POST['id'], 'nonce' );
  1141 
  1219 
  1142 		if ( ! current_user_can( 'edit_theme_options' ) ) {
  1220 		if ( ! current_user_can( 'edit_theme_options' ) ) {
  1173 		/** This filter is documented in wp-admin/custom-header.php */
  1251 		/** This filter is documented in wp-admin/custom-header.php */
  1174 		$cropped = apply_filters( 'wp_create_file_in_uploads', $cropped, $attachment_id ); // For replication
  1252 		$cropped = apply_filters( 'wp_create_file_in_uploads', $cropped, $attachment_id ); // For replication
  1175 
  1253 
  1176 		$object = $this->create_attachment_object( $cropped, $attachment_id );
  1254 		$object = $this->create_attachment_object( $cropped, $attachment_id );
  1177 
  1255 
  1178 		unset( $object['ID'] );
  1256 		$previous = $this->get_previous_crop( $object );
       
  1257 
       
  1258 		if ( $previous ) {
       
  1259 			$object['ID'] = $previous;
       
  1260 		} else {
       
  1261 			unset( $object['ID'] );
       
  1262 		}
  1179 
  1263 
  1180 		$new_attachment_id = $this->insert_attachment( $object, $cropped );
  1264 		$new_attachment_id = $this->insert_attachment( $object, $cropped );
  1181 
  1265 
  1182 		$object['attachment_id'] = $new_attachment_id;
  1266 		$object['attachment_id'] = $new_attachment_id;
       
  1267 		$object['url']           = wp_get_attachment_url( $new_attachment_id );;
  1183 		$object['width']         = $dimensions['dst_width'];
  1268 		$object['width']         = $dimensions['dst_width'];
  1184 		$object['height']        = $dimensions['dst_height'];
  1269 		$object['height']        = $dimensions['dst_height'];
  1185 
  1270 
  1186 		wp_send_json_success( $object );
  1271 		wp_send_json_success( $object );
  1187 	}
  1272 	}
  1190 	 * Given an attachment ID for a header image, updates its "last used"
  1275 	 * Given an attachment ID for a header image, updates its "last used"
  1191 	 * timestamp to now.
  1276 	 * timestamp to now.
  1192 	 *
  1277 	 *
  1193 	 * Triggered when the user tries adds a new header image from the
  1278 	 * Triggered when the user tries adds a new header image from the
  1194 	 * Media Manager, even if s/he doesn't save that change.
  1279 	 * Media Manager, even if s/he doesn't save that change.
       
  1280 	 *
       
  1281 	 * @since 3.9.0
  1195 	 */
  1282 	 */
  1196 	public function ajax_header_add() {
  1283 	public function ajax_header_add() {
  1197 		check_ajax_referer( 'header-add', 'nonce' );
  1284 		check_ajax_referer( 'header-add', 'nonce' );
  1198 
  1285 
  1199 		if ( ! current_user_can( 'edit_theme_options' ) ) {
  1286 		if ( ! current_user_can( 'edit_theme_options' ) ) {
  1216 	 * Given an attachment ID for a header image, unsets it as a user-uploaded
  1303 	 * Given an attachment ID for a header image, unsets it as a user-uploaded
  1217 	 * header image for the current theme.
  1304 	 * header image for the current theme.
  1218 	 *
  1305 	 *
  1219 	 * Triggered when the user clicks the overlay "X" button next to each image
  1306 	 * Triggered when the user clicks the overlay "X" button next to each image
  1220 	 * choice in the Customizer's Header tool.
  1307 	 * choice in the Customizer's Header tool.
       
  1308 	 *
       
  1309 	 * @since 3.9.0
  1221 	 */
  1310 	 */
  1222 	public function ajax_header_remove() {
  1311 	public function ajax_header_remove() {
  1223 		check_ajax_referer( 'header-remove', 'nonce' );
  1312 		check_ajax_referer( 'header-remove', 'nonce' );
  1224 
  1313 
  1225 		if ( ! current_user_can( 'edit_theme_options' ) ) {
  1314 		if ( ! current_user_can( 'edit_theme_options' ) ) {
  1236 		delete_post_meta( $attachment_id, '_wp_attachment_is_custom_header', get_stylesheet() );
  1325 		delete_post_meta( $attachment_id, '_wp_attachment_is_custom_header', get_stylesheet() );
  1237 
  1326 
  1238 		wp_send_json_success();
  1327 		wp_send_json_success();
  1239 	}
  1328 	}
  1240 
  1329 
       
  1330 	/**
       
  1331 	 * Updates the last-used postmeta on a header image attachment after saving a new header image via the Customizer.
       
  1332 	 *
       
  1333 	 * @since 3.9.0
       
  1334 	 *
       
  1335 	 * @param WP_Customize_Manager $wp_customize Customize manager.
       
  1336 	 */
  1241 	public function customize_set_last_used( $wp_customize ) {
  1337 	public function customize_set_last_used( $wp_customize ) {
  1242 		$data = $wp_customize->get_setting( 'header_image_data' )->post_value();
  1338 
       
  1339 		$header_image_data_setting = $wp_customize->get_setting( 'header_image_data' );
       
  1340 		if ( ! $header_image_data_setting ) {
       
  1341 			return;
       
  1342 		}
       
  1343 		$data = $header_image_data_setting->post_value();
  1243 
  1344 
  1244 		if ( ! isset( $data['attachment_id'] ) ) {
  1345 		if ( ! isset( $data['attachment_id'] ) ) {
  1245 			return;
  1346 			return;
  1246 		}
  1347 		}
  1247 
  1348 
  1248 		$attachment_id = $data['attachment_id'];
  1349 		$attachment_id = $data['attachment_id'];
  1249 		$key = '_wp_attachment_custom_header_last_used_' . get_stylesheet();
  1350 		$key = '_wp_attachment_custom_header_last_used_' . get_stylesheet();
  1250 		update_post_meta( $attachment_id, $key, time() );
  1351 		update_post_meta( $attachment_id, $key, time() );
  1251 	}
  1352 	}
  1252 
  1353 
       
  1354 	/**
       
  1355 	 * Gets the details of default header images if defined.
       
  1356 	 *
       
  1357 	 * @since 3.9.0
       
  1358 	 *
       
  1359 	 * @return array Default header images.
       
  1360 	 */
  1253 	public function get_default_header_images() {
  1361 	public function get_default_header_images() {
  1254 		$this->process_default_headers();
  1362 		$this->process_default_headers();
  1255 
  1363 
  1256 		// Get the default image if there is one.
  1364 		// Get the default image if there is one.
  1257 		$default = get_theme_support( 'custom-header', 'default-image' );
  1365 		$default = get_theme_support( 'custom-header', 'default-image' );
  1281 			'thumbnail_url' => $default,
  1389 			'thumbnail_url' => $default,
  1282 			'description'   => 'Default'
  1390 			'description'   => 'Default'
  1283 		);
  1391 		);
  1284 
  1392 
  1285 		// The rest of the set comes after.
  1393 		// The rest of the set comes after.
  1286 		$header_images = array_merge( $header_images, $this->default_headers );
  1394 		return array_merge( $header_images, $this->default_headers );
  1287 		return $header_images;
  1395 	}
  1288 	}
  1396 
  1289 
  1397 	/**
       
  1398 	 * Gets the previously uploaded header images.
       
  1399 	 *
       
  1400 	 * @since 3.9.0
       
  1401 	 *
       
  1402 	 * @return array Uploaded header images.
       
  1403 	 */
  1290 	public function get_uploaded_header_images() {
  1404 	public function get_uploaded_header_images() {
  1291 		$header_images = get_uploaded_header_images();
  1405 		$header_images = get_uploaded_header_images();
  1292 		$timestamp_key = '_wp_attachment_custom_header_last_used_' . get_stylesheet();
  1406 		$timestamp_key = '_wp_attachment_custom_header_last_used_' . get_stylesheet();
  1293 		$alt_text_key = '_wp_attachment_image_alt';
  1407 		$alt_text_key = '_wp_attachment_image_alt';
  1294 
  1408 
  1298 			$header_image['alt_text'] = isset( $header_meta[ $alt_text_key ] ) ? $header_meta[ $alt_text_key ] : '';
  1412 			$header_image['alt_text'] = isset( $header_meta[ $alt_text_key ] ) ? $header_meta[ $alt_text_key ] : '';
  1299 		}
  1413 		}
  1300 
  1414 
  1301 		return $header_images;
  1415 		return $header_images;
  1302 	}
  1416 	}
       
  1417 
       
  1418 	/**
       
  1419 	 * Get the ID of a previous crop from the same base image.
       
  1420 	 *
       
  1421 	 * @since 4.9.0
       
  1422 	 *
       
  1423 	 * @param  array $object A crop attachment object.
       
  1424 	 * @return int|false An attachment ID if one exists. False if none.
       
  1425 	 */
       
  1426 	public function get_previous_crop( $object ) {
       
  1427 		$header_images = $this->get_uploaded_header_images();
       
  1428 
       
  1429 		// Bail early if there are no header images.
       
  1430 		if ( empty( $header_images ) ) {
       
  1431 			return false;
       
  1432 		}
       
  1433 
       
  1434 		$previous = false;
       
  1435 
       
  1436 		foreach ( $header_images as $image ) {
       
  1437 			if ( $image['attachment_parent'] === $object['post_parent'] ) {
       
  1438 				$previous = $image['attachment_id'];
       
  1439 				break;
       
  1440 			}
       
  1441 		}
       
  1442 
       
  1443 		return $previous;
       
  1444 	}
  1303 }
  1445 }