wp/wp-admin/includes/class-custom-image-header.php
changeset 21 48c4eec2b7e6
parent 19 3d72ae0968f4
child 22 8c2e4d02f4ef
equal deleted inserted replaced
20:7b1b88e27a20 21:48c4eec2b7e6
     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  */
    13  */
       
    14 #[AllowDynamicProperties]
    14 class Custom_Image_Header {
    15 class Custom_Image_Header {
    15 
    16 
    16 	/**
    17 	/**
    17 	 * Callback for administration header.
    18 	 * Callback for administration header.
    18 	 *
    19 	 *
    44 	 * @var bool
    45 	 * @var bool
    45 	 */
    46 	 */
    46 	private $updated;
    47 	private $updated;
    47 
    48 
    48 	/**
    49 	/**
    49 	 * Constructor - Register administration header callback.
    50 	 * Constructor - Registers administration header callback.
    50 	 *
    51 	 *
    51 	 * @since 2.1.0
    52 	 * @since 2.1.0
    52 	 * @param callable $admin_header_callback
    53 	 *
    53 	 * @param callable $admin_image_div_callback Optional custom image div output callback.
    54 	 * @param callable $admin_header_callback    Administration header callback.
       
    55 	 * @param callable $admin_image_div_callback Optional. Custom image div output callback.
       
    56 	 *                                           Default empty string.
    54 	 */
    57 	 */
    55 	public function __construct( $admin_header_callback, $admin_image_div_callback = '' ) {
    58 	public function __construct( $admin_header_callback, $admin_image_div_callback = '' ) {
    56 		$this->admin_header_callback    = $admin_header_callback;
    59 		$this->admin_header_callback    = $admin_header_callback;
    57 		$this->admin_image_div_callback = $admin_image_div_callback;
    60 		$this->admin_image_div_callback = $admin_image_div_callback;
    58 
    61 
    63 		add_action( 'wp_ajax_custom-header-add', array( $this, 'ajax_header_add' ) );
    66 		add_action( 'wp_ajax_custom-header-add', array( $this, 'ajax_header_add' ) );
    64 		add_action( 'wp_ajax_custom-header-remove', array( $this, 'ajax_header_remove' ) );
    67 		add_action( 'wp_ajax_custom-header-remove', array( $this, 'ajax_header_remove' ) );
    65 	}
    68 	}
    66 
    69 
    67 	/**
    70 	/**
    68 	 * Set up the hooks for the Custom Header admin page.
    71 	 * Sets up the hooks for the Custom Header admin page.
    69 	 *
    72 	 *
    70 	 * @since 2.1.0
    73 	 * @since 2.1.0
    71 	 */
    74 	 */
    72 	public function init() {
    75 	public function init() {
    73 		$page = add_theme_page( __( 'Header' ), __( 'Header' ), 'edit_theme_options', 'custom-header', array( $this, 'admin_page' ) );
    76 		$page = add_theme_page(
       
    77 			_x( 'Header', 'custom image header' ),
       
    78 			_x( 'Header', 'custom image header' ),
       
    79 			'edit_theme_options',
       
    80 			'custom-header',
       
    81 			array( $this, 'admin_page' )
       
    82 		);
    74 
    83 
    75 		if ( ! $page ) {
    84 		if ( ! $page ) {
    76 			return;
    85 			return;
    77 		}
    86 		}
    78 
    87 
   132 		);
   141 		);
   133 
   142 
   134 		get_current_screen()->set_help_sidebar(
   143 		get_current_screen()->set_help_sidebar(
   135 			'<p><strong>' . __( 'For more information:' ) . '</strong></p>' .
   144 			'<p><strong>' . __( 'For more information:' ) . '</strong></p>' .
   136 			'<p>' . __( '<a href="https://codex.wordpress.org/Appearance_Header_Screen">Documentation on Custom Header</a>' ) . '</p>' .
   145 			'<p>' . __( '<a href="https://codex.wordpress.org/Appearance_Header_Screen">Documentation on Custom Header</a>' ) . '</p>' .
   137 			'<p>' . __( '<a href="https://wordpress.org/support/">Support</a>' ) . '</p>'
   146 			'<p>' . __( '<a href="https://wordpress.org/support/forums/">Support forums</a>' ) . '</p>'
   138 		);
   147 		);
   139 	}
   148 	}
   140 
   149 
   141 	/**
   150 	/**
   142 	 * Get the current step.
   151 	 * Gets the current step.
   143 	 *
   152 	 *
   144 	 * @since 2.6.0
   153 	 * @since 2.6.0
   145 	 *
   154 	 *
   146 	 * @return int Current step.
   155 	 * @return int Current step.
   147 	 */
   156 	 */
   160 
   169 
   161 		return $step;
   170 		return $step;
   162 	}
   171 	}
   163 
   172 
   164 	/**
   173 	/**
   165 	 * Set up the enqueue for the JavaScript files.
   174 	 * Sets up the enqueue for the JavaScript files.
   166 	 *
   175 	 *
   167 	 * @since 2.1.0
   176 	 * @since 2.1.0
   168 	 */
   177 	 */
   169 	public function js_includes() {
   178 	public function js_includes() {
   170 		$step = $this->step();
   179 		$step = $this->step();
   179 			wp_enqueue_script( 'imgareaselect' );
   188 			wp_enqueue_script( 'imgareaselect' );
   180 		}
   189 		}
   181 	}
   190 	}
   182 
   191 
   183 	/**
   192 	/**
   184 	 * Set up the enqueue for the CSS files
   193 	 * Sets up the enqueue for the CSS files.
   185 	 *
   194 	 *
   186 	 * @since 2.7.0
   195 	 * @since 2.7.0
   187 	 */
   196 	 */
   188 	public function css_includes() {
   197 	public function css_includes() {
   189 		$step = $this->step();
   198 		$step = $this->step();
   194 			wp_enqueue_style( 'imgareaselect' );
   203 			wp_enqueue_style( 'imgareaselect' );
   195 		}
   204 		}
   196 	}
   205 	}
   197 
   206 
   198 	/**
   207 	/**
   199 	 * Execute custom header modification.
   208 	 * Executes custom header modification.
   200 	 *
   209 	 *
   201 	 * @since 2.6.0
   210 	 * @since 2.6.0
   202 	 */
   211 	 */
   203 	public function take_action() {
   212 	public function take_action() {
   204 		if ( ! current_user_can( 'edit_theme_options' ) ) {
   213 		if ( ! current_user_can( 'edit_theme_options' ) ) {
   253 			return;
   262 			return;
   254 		}
   263 		}
   255 	}
   264 	}
   256 
   265 
   257 	/**
   266 	/**
   258 	 * Process the default headers
   267 	 * Processes the default headers.
   259 	 *
   268 	 *
   260 	 * @since 3.0.0
   269 	 * @since 3.0.0
   261 	 *
   270 	 *
   262 	 * @global array $_wp_default_headers
   271 	 * @global array $_wp_default_headers
   263 	 */
   272 	 */
   290 			);
   299 			);
   291 		}
   300 		}
   292 	}
   301 	}
   293 
   302 
   294 	/**
   303 	/**
   295 	 * Display UI for selecting one of several default headers.
   304 	 * Displays UI for selecting one of several default headers.
   296 	 *
   305 	 *
   297 	 * Show the random image option if this theme has multiple header images.
   306 	 * Shows the random image option if this theme has multiple header images.
   298 	 * Random image option is on by default if no header has been set.
   307 	 * Random image option is on by default if no header has been set.
   299 	 *
   308 	 *
   300 	 * @since 3.0.0
   309 	 * @since 3.0.0
   301 	 *
   310 	 *
   302 	 * @param string $type The header type. One of 'default' (for the Uploaded Images control)
   311 	 * @param string $type The header type. One of 'default' (for the Uploaded Images control)
   329 			echo '<label><input name="default-header" type="radio" value="' . esc_attr( $header_key ) . '" ' . checked( $header_url, get_theme_mod( 'header_image' ), false ) . ' />';
   338 			echo '<label><input name="default-header" type="radio" value="' . esc_attr( $header_key ) . '" ' . checked( $header_url, get_theme_mod( 'header_image' ), false ) . ' />';
   330 			$width = '';
   339 			$width = '';
   331 			if ( ! empty( $header['attachment_id'] ) ) {
   340 			if ( ! empty( $header['attachment_id'] ) ) {
   332 				$width = ' width="230"';
   341 				$width = ' width="230"';
   333 			}
   342 			}
   334 			echo '<img src="' . set_url_scheme( $header_thumbnail ) . '" alt="' . esc_attr( $header_alt_text ) . '"' . $width . ' /></label>';
   343 			echo '<img src="' . esc_url( set_url_scheme( $header_thumbnail ) ) . '" alt="' . esc_attr( $header_alt_text ) . '"' . $width . ' /></label>';
   335 			echo '</div>';
   344 			echo '</div>';
   336 		}
   345 		}
   337 
   346 
   338 		echo '<div class="clear"></div></div>';
   347 		echo '<div class="clear"></div></div>';
   339 	}
   348 	}
   340 
   349 
   341 	/**
   350 	/**
   342 	 * Execute JavaScript depending on step.
   351 	 * Executes JavaScript depending on step.
   343 	 *
   352 	 *
   344 	 * @since 2.1.0
   353 	 * @since 2.1.0
   345 	 */
   354 	 */
   346 	public function js() {
   355 	public function js() {
   347 		$step = $this->step();
   356 		$step = $this->step();
   352 			$this->js_2();
   361 			$this->js_2();
   353 		}
   362 		}
   354 	}
   363 	}
   355 
   364 
   356 	/**
   365 	/**
   357 	 * Display JavaScript based on Step 1 and 3.
   366 	 * Displays JavaScript based on Step 1 and 3.
   358 	 *
   367 	 *
   359 	 * @since 2.6.0
   368 	 * @since 2.6.0
   360 	 */
   369 	 */
   361 	public function js_1() {
   370 	public function js_1() {
   362 		$default_color = '';
   371 		$default_color = '';
   363 		if ( current_theme_supports( 'custom-header', 'default-text-color' ) ) {
   372 		if ( current_theme_supports( 'custom-header', 'default-text-color' ) ) {
   364 			$default_color = get_theme_support( 'custom-header', 'default-text-color' );
   373 			$default_color = get_theme_support( 'custom-header', 'default-text-color' );
   365 			if ( $default_color && false === strpos( $default_color, '#' ) ) {
   374 			if ( $default_color && ! str_contains( $default_color, '#' ) ) {
   366 				$default_color = '#' . $default_color;
   375 				$default_color = '#' . $default_color;
   367 			}
   376 			}
   368 		}
   377 		}
   369 		?>
   378 		?>
   370 <script type="text/javascript">
   379 <script type="text/javascript">
   413 </script>
   422 </script>
   414 		<?php
   423 		<?php
   415 	}
   424 	}
   416 
   425 
   417 	/**
   426 	/**
   418 	 * Display JavaScript based on Step 2.
   427 	 * Displays JavaScript based on Step 2.
   419 	 *
   428 	 *
   420 	 * @since 2.6.0
   429 	 * @since 2.6.0
   421 	 */
   430 	 */
   422 	public function js_2() {
   431 	public function js_2() {
   423 
   432 
   489 </script>
   498 </script>
   490 		<?php
   499 		<?php
   491 	}
   500 	}
   492 
   501 
   493 	/**
   502 	/**
   494 	 * Display first step of custom header image page.
   503 	 * Displays first step of custom header image page.
   495 	 *
   504 	 *
   496 	 * @since 2.1.0
   505 	 * @since 2.1.0
   497 	 */
   506 	 */
   498 	public function step_1() {
   507 	public function step_1() {
   499 		$this->process_default_headers();
   508 		$this->process_default_headers();
   500 		?>
   509 		?>
   501 
   510 
   502 <div class="wrap">
   511 <div class="wrap">
   503 <h1><?php _e( 'Custom Header' ); ?></h1>
   512 <h1><?php _e( 'Custom Header' ); ?></h1>
   504 
   513 
   505 		<?php if ( current_user_can( 'customize' ) ) { ?>
   514 		<?php
   506 <div class="notice notice-info hide-if-no-customize">
   515 		if ( current_user_can( 'customize' ) ) {
   507 	<p>
   516 			$message = sprintf(
   508 			<?php
       
   509 			printf(
       
   510 				/* translators: %s: URL to header image configuration in Customizer. */
   517 				/* translators: %s: URL to header image configuration in Customizer. */
   511 				__( 'You can now manage and live-preview Custom Header in the <a href="%s">Customizer</a>.' ),
   518 				__( 'You can now manage and live-preview Custom Header in the <a href="%s">Customizer</a>.' ),
   512 				admin_url( 'customize.php?autofocus[control]=header_image' )
   519 				admin_url( 'customize.php?autofocus[control]=header_image' )
   513 			);
   520 			);
   514 			?>
   521 			wp_admin_notice(
   515 	</p>
   522 				$message,
   516 </div>
   523 				array(
   517 		<?php } ?>
   524 					'type'               => 'info',
   518 
   525 					'additional_classes' => array( 'hide-if-no-customize' ),
   519 		<?php if ( ! empty( $this->updated ) ) { ?>
   526 				)
   520 <div id="message" class="updated">
   527 			);
   521 	<p>
   528 		}
   522 			<?php
   529 
   523 			/* translators: %s: Home URL. */
   530 		if ( ! empty( $this->updated ) ) {
   524 			printf( __( 'Header updated. <a href="%s">Visit your site</a> to see how it looks.' ), home_url( '/' ) );
   531 			$updated_message = sprintf(
   525 			?>
   532 				/* translators: %s: Home URL. */
   526 	</p>
   533 				__( 'Header updated. <a href="%s">Visit your site</a> to see how it looks.' ),
   527 </div>
   534 				esc_url( home_url( '/' ) )
   528 		<?php } ?>
   535 			);
       
   536 			wp_admin_notice(
       
   537 				$updated_message,
       
   538 				array(
       
   539 					'id'                 => 'message',
       
   540 					'additional_classes' => array( 'updated' ),
       
   541 				)
       
   542 			);
       
   543 		}
       
   544 		?>
   529 
   545 
   530 <h2><?php _e( 'Header Image' ); ?></h2>
   546 <h2><?php _e( 'Header Image' ); ?></h2>
   531 
   547 
   532 <table class="form-table" role="presentation">
   548 <table class="form-table" role="presentation">
   533 <tbody>
   549 <tbody>
   694 			?>
   710 			?>
   695 <tr>
   711 <tr>
   696 <th scope="row"><?php _e( 'Default Images' ); ?></th>
   712 <th scope="row"><?php _e( 'Default Images' ); ?></th>
   697 <td>
   713 <td>
   698 			<?php if ( current_theme_supports( 'custom-header', 'uploads' ) ) : ?>
   714 			<?php if ( current_theme_supports( 'custom-header', 'uploads' ) ) : ?>
   699 	<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>
   715 	<p><?php _e( 'If you do not want to upload your own image, you can use one of these cool headers, or show a random one.' ); ?></p>
   700 	<?php else : ?>
   716 	<?php else : ?>
   701 	<p><?php _e( 'You can use one of these cool headers or show a random one on each page.' ); ?></p>
   717 	<p><?php _e( 'You can use one of these cool headers or show a random one on each page.' ); ?></p>
   702 	<?php endif; ?>
   718 	<?php endif; ?>
   703 			<?php
   719 			<?php
   704 			$this->show_header_selector( 'default' );
   720 			$this->show_header_selector( 'default' );
   759 	<p>
   775 	<p>
   760 			<?php
   776 			<?php
   761 			$default_color = '';
   777 			$default_color = '';
   762 			if ( current_theme_supports( 'custom-header', 'default-text-color' ) ) {
   778 			if ( current_theme_supports( 'custom-header', 'default-text-color' ) ) {
   763 				$default_color = get_theme_support( 'custom-header', 'default-text-color' );
   779 				$default_color = get_theme_support( 'custom-header', 'default-text-color' );
   764 				if ( $default_color && false === strpos( $default_color, '#' ) ) {
   780 				if ( $default_color && ! str_contains( $default_color, '#' ) ) {
   765 					$default_color = '#' . $default_color;
   781 					$default_color = '#' . $default_color;
   766 				}
   782 				}
   767 			}
   783 			}
   768 
   784 
   769 			$default_color_attr = $default_color ? ' data-default-color="' . esc_attr( $default_color ) . '"' : '';
   785 			$default_color_attr = $default_color ? ' data-default-color="' . esc_attr( $default_color ) . '"' : '';
   770 
   786 
   771 			$header_textcolor = display_header_text() ? get_header_textcolor() : get_theme_support( 'custom-header', 'default-text-color' );
   787 			$header_textcolor = display_header_text() ? get_header_textcolor() : get_theme_support( 'custom-header', 'default-text-color' );
   772 			if ( $header_textcolor && false === strpos( $header_textcolor, '#' ) ) {
   788 			if ( $header_textcolor && ! str_contains( $header_textcolor, '#' ) ) {
   773 				$header_textcolor = '#' . $header_textcolor;
   789 				$header_textcolor = '#' . $header_textcolor;
   774 			}
   790 			}
   775 
   791 
   776 			echo '<input type="text" name="text-color" id="text-color" value="' . esc_attr( $header_textcolor ) . '"' . $default_color_attr . ' />';
   792 			echo '<input type="text" name="text-color" id="text-color" value="' . esc_attr( $header_textcolor ) . '"' . $default_color_attr . ' />';
   777 			if ( $default_color ) {
   793 			if ( $default_color ) {
   803 
   819 
   804 		<?php
   820 		<?php
   805 	}
   821 	}
   806 
   822 
   807 	/**
   823 	/**
   808 	 * Display second step of custom header image page.
   824 	 * Displays second step of custom header image page.
   809 	 *
   825 	 *
   810 	 * @since 2.1.0
   826 	 * @since 2.1.0
   811 	 */
   827 	 */
   812 	public function step_2() {
   828 	public function step_2() {
   813 		check_admin_referer( 'custom-header-upload', '_wpnonce-custom-header-upload' );
   829 		check_admin_referer( 'custom-header-upload', '_wpnonce-custom-header-upload' );
   866 			}
   882 			}
   867 
   883 
   868 			$this->set_header_image( compact( 'url', 'attachment_id', 'width', 'height' ) );
   884 			$this->set_header_image( compact( 'url', 'attachment_id', 'width', 'height' ) );
   869 
   885 
   870 			/**
   886 			/**
   871 			 * Fires after the header image is set or an error is returned.
   887 			 * Filters the attachment file path after the custom header or background image is set.
       
   888 			 *
       
   889 			 * Used for file replication.
   872 			 *
   890 			 *
   873 			 * @since 2.1.0
   891 			 * @since 2.1.0
   874 			 *
   892 			 *
   875 			 * @param string $file          Path to the file.
   893 			 * @param string $file          Path to the file.
   876 			 * @param int    $attachment_id Attachment ID.
   894 			 * @param int    $attachment_id Attachment ID.
   877 			 */
   895 			 */
   878 			do_action( 'wp_create_file_in_uploads', $file, $attachment_id ); // For replication.
   896 			$file = apply_filters( 'wp_create_file_in_uploads', $file, $attachment_id ); // For replication.
   879 
   897 
   880 			return $this->finished();
   898 			return $this->finished();
   881 		} elseif ( $width > $max_width ) {
   899 		} elseif ( $width > $max_width ) {
   882 			$oitar = $width / $max_width;
   900 			$oitar = $width / $max_width;
   883 
   901 
   914 <form method="post" action="<?php echo esc_url( add_query_arg( 'step', 3 ) ); ?>">
   932 <form method="post" action="<?php echo esc_url( add_query_arg( 'step', 3 ) ); ?>">
   915 	<p class="hide-if-no-js"><?php _e( 'Choose the part of the image you want to use as your header.' ); ?></p>
   933 	<p class="hide-if-no-js"><?php _e( 'Choose the part of the image you want to use as your header.' ); ?></p>
   916 	<p class="hide-if-js"><strong><?php _e( 'You need JavaScript to choose a part of the image.' ); ?></strong></p>
   934 	<p class="hide-if-js"><strong><?php _e( 'You need JavaScript to choose a part of the image.' ); ?></strong></p>
   917 
   935 
   918 	<div id="crop_image" style="position: relative">
   936 	<div id="crop_image" style="position: relative">
   919 		<img src="<?php echo esc_url( $url ); ?>" id="upload" width="<?php echo $width; ?>" height="<?php echo $height; ?>" alt="" />
   937 		<img src="<?php echo esc_url( $url ); ?>" id="upload" width="<?php echo esc_attr( $width ); ?>" height="<?php echo esc_attr( $height ); ?>" alt="" />
   920 	</div>
   938 	</div>
   921 
   939 
   922 	<input type="hidden" name="x1" id="x1" value="0" />
   940 	<input type="hidden" name="x1" id="x1" value="0" />
   923 	<input type="hidden" name="y1" id="y1" value="0" />
   941 	<input type="hidden" name="y1" id="y1" value="0" />
   924 	<input type="hidden" name="width" id="width" value="<?php echo esc_attr( $width ); ?>" />
   942 	<input type="hidden" name="width" id="width" value="<?php echo esc_attr( $width ); ?>" />
   946 		<?php
   964 		<?php
   947 	}
   965 	}
   948 
   966 
   949 
   967 
   950 	/**
   968 	/**
   951 	 * Upload the file to be cropped in the second step.
   969 	 * Uploads the file to be cropped in the second step.
   952 	 *
   970 	 *
   953 	 * @since 3.4.0
   971 	 * @since 3.4.0
   954 	 */
   972 	 */
   955 	public function step_2_manage_upload() {
   973 	public function step_2_manage_upload() {
   956 		$overrides = array( 'test_form' => false );
   974 		$overrides = array( 'test_form' => false );
   987 
  1005 
   988 		return compact( 'attachment_id', 'file', 'filename', 'url', 'type' );
  1006 		return compact( 'attachment_id', 'file', 'filename', 'url', 'type' );
   989 	}
  1007 	}
   990 
  1008 
   991 	/**
  1009 	/**
   992 	 * Display third step of custom header image page.
  1010 	 * Displays third step of custom header image page.
   993 	 *
  1011 	 *
   994 	 * @since 2.1.0
  1012 	 * @since 2.1.0
   995 	 * @since 4.4.0 Switched to using wp_get_attachment_url() instead of the guid
  1013 	 * @since 4.4.0 Switched to using wp_get_attachment_url() instead of the guid
   996 	 *              for retrieving the header image URL.
  1014 	 *              for retrieving the header image URL.
   997 	 */
  1015 	 */
  1057 		}
  1075 		}
  1058 
  1076 
  1059 		/** This filter is documented in wp-admin/includes/class-custom-image-header.php */
  1077 		/** This filter is documented in wp-admin/includes/class-custom-image-header.php */
  1060 		$cropped = apply_filters( 'wp_create_file_in_uploads', $cropped, $attachment_id ); // For replication.
  1078 		$cropped = apply_filters( 'wp_create_file_in_uploads', $cropped, $attachment_id ); // For replication.
  1061 
  1079 
  1062 		$attachment = $this->create_attachment_object( $cropped, $attachment_id );
  1080 		$attachment = wp_copy_parent_attachment_properties( $cropped, $attachment_id, 'custom-header' );
  1063 
  1081 
  1064 		if ( ! empty( $_POST['create-new-attachment'] ) ) {
  1082 		if ( ! empty( $_POST['create-new-attachment'] ) ) {
  1065 			unset( $attachment['ID'] );
  1083 			unset( $attachment['ID'] );
  1066 		}
  1084 		}
  1067 
  1085 
  1083 
  1101 
  1084 		return $this->finished();
  1102 		return $this->finished();
  1085 	}
  1103 	}
  1086 
  1104 
  1087 	/**
  1105 	/**
  1088 	 * Display last step of custom header image page.
  1106 	 * Displays last step of custom header image page.
  1089 	 *
  1107 	 *
  1090 	 * @since 2.1.0
  1108 	 * @since 2.1.0
  1091 	 */
  1109 	 */
  1092 	public function finished() {
  1110 	public function finished() {
  1093 		$this->updated = true;
  1111 		$this->updated = true;
  1094 		$this->step_1();
  1112 		$this->step_1();
  1095 	}
  1113 	}
  1096 
  1114 
  1097 	/**
  1115 	/**
  1098 	 * Display the page based on the current step.
  1116 	 * Displays the page based on the current step.
  1099 	 *
  1117 	 *
  1100 	 * @since 2.1.0
  1118 	 * @since 2.1.0
  1101 	 */
  1119 	 */
  1102 	public function admin_page() {
  1120 	public function admin_page() {
  1103 		if ( ! current_user_can( 'edit_theme_options' ) ) {
  1121 		if ( ! current_user_can( 'edit_theme_options' ) ) {
  1138 	public function filter_upload_tabs( $tabs ) {
  1156 	public function filter_upload_tabs( $tabs ) {
  1139 		return $tabs;
  1157 		return $tabs;
  1140 	}
  1158 	}
  1141 
  1159 
  1142 	/**
  1160 	/**
  1143 	 * Choose a header image, selected from existing uploaded and default headers,
  1161 	 * Chooses a header image, selected from existing uploaded and default headers,
  1144 	 * or provide an array of uploaded header data (either new, or from media library).
  1162 	 * or provides an array of uploaded header data (either new, or from media library).
  1145 	 *
  1163 	 *
  1146 	 * @since 3.4.0
  1164 	 * @since 3.4.0
  1147 	 *
  1165 	 *
  1148 	 * @param mixed $choice Which header image to select. Allows for values of 'random-default-image',
  1166 	 * @param mixed $choice Which header image to select. Allows for values of 'random-default-image',
  1149 	 *  for randomly cycling among the default images; 'random-uploaded-image', for randomly cycling
  1167 	 *                      for randomly cycling among the default images; 'random-uploaded-image',
  1150 	 *  among the uploaded images; the key of a default image registered for that theme; and
  1168 	 *                      for randomly cycling among the uploaded images; the key of a default image
  1151 	 *  the key of an image uploaded for that theme (the attachment ID of the image).
  1169 	 *                      registered for that theme; and the key of an image uploaded for that theme
  1152 	 *  Or an array of arguments: attachment_id, url, width, height. All are required.
  1170 	 *                      (the attachment ID of the image). Or an array of arguments: attachment_id,
       
  1171 	 *                      url, width, height. All are required.
  1153 	 */
  1172 	 */
  1154 	final public function set_header_image( $choice ) {
  1173 	final public function set_header_image( $choice ) {
  1155 		if ( is_array( $choice ) || is_object( $choice ) ) {
  1174 		if ( is_array( $choice ) || is_object( $choice ) ) {
  1156 			$choice = (array) $choice;
  1175 			$choice = (array) $choice;
  1157 
  1176 
  1158 			if ( ! isset( $choice['attachment_id'] ) || ! isset( $choice['url'] ) ) {
  1177 			if ( ! isset( $choice['attachment_id'] ) || ! isset( $choice['url'] ) ) {
  1159 				return;
  1178 				return;
  1160 			}
  1179 			}
  1161 
  1180 
  1162 			$choice['url'] = esc_url_raw( $choice['url'] );
  1181 			$choice['url'] = sanitize_url( $choice['url'] );
  1163 
  1182 
  1164 			$header_image_data = (object) array(
  1183 			$header_image_data = (object) array(
  1165 				'attachment_id' => $choice['attachment_id'],
  1184 				'attachment_id' => $choice['attachment_id'],
  1166 				'url'           => $choice['url'],
  1185 				'url'           => $choice['url'],
  1167 				'thumbnail_url' => $choice['url'],
  1186 				'thumbnail_url' => $choice['url'],
  1195 			} else {
  1214 			} else {
  1196 				return;
  1215 				return;
  1197 			}
  1216 			}
  1198 		}
  1217 		}
  1199 
  1218 
  1200 		set_theme_mod( 'header_image', esc_url_raw( $header_image_data['url'] ) );
  1219 		set_theme_mod( 'header_image', sanitize_url( $header_image_data['url'] ) );
  1201 		set_theme_mod( 'header_image_data', $header_image_data );
  1220 		set_theme_mod( 'header_image_data', $header_image_data );
  1202 	}
  1221 	}
  1203 
  1222 
  1204 	/**
  1223 	/**
  1205 	 * Remove a header image.
  1224 	 * Removes a header image.
  1206 	 *
  1225 	 *
  1207 	 * @since 3.4.0
  1226 	 * @since 3.4.0
  1208 	 */
  1227 	 */
  1209 	final public function remove_header_image() {
  1228 	final public function remove_header_image() {
  1210 		$this->set_header_image( 'remove-header' );
  1229 		$this->set_header_image( 'remove-header' );
  1211 	}
  1230 	}
  1212 
  1231 
  1213 	/**
  1232 	/**
  1214 	 * Reset a header image to the default image for the theme.
  1233 	 * Resets a header image to the default image for the theme.
  1215 	 *
  1234 	 *
  1216 	 * This method does not do anything if the theme does not have a default header image.
  1235 	 * This method does not do anything if the theme does not have a default header image.
  1217 	 *
  1236 	 *
  1218 	 * @since 3.4.0
  1237 	 * @since 3.4.0
  1219 	 */
  1238 	 */
  1239 		set_theme_mod( 'header_image', $default );
  1258 		set_theme_mod( 'header_image', $default );
  1240 		set_theme_mod( 'header_image_data', (object) $default_data );
  1259 		set_theme_mod( 'header_image_data', (object) $default_data );
  1241 	}
  1260 	}
  1242 
  1261 
  1243 	/**
  1262 	/**
  1244 	 * Calculate width and height based on what the currently selected theme supports.
  1263 	 * Calculates width and height based on what the currently selected theme supports.
  1245 	 *
  1264 	 *
  1246 	 * @since 3.9.0
  1265 	 * @since 3.9.0
  1247 	 *
  1266 	 *
  1248 	 * @param array $dimensions
  1267 	 * @param array $dimensions
  1249 	 * @return array dst_height and dst_width of header image.
  1268 	 * @return array dst_height and dst_width of header image.
  1290 
  1309 
  1291 		return $dst;
  1310 		return $dst;
  1292 	}
  1311 	}
  1293 
  1312 
  1294 	/**
  1313 	/**
  1295 	 * Create an attachment 'object'.
  1314 	 * Creates an attachment 'object'.
  1296 	 *
  1315 	 *
  1297 	 * @since 3.9.0
  1316 	 * @since 3.9.0
       
  1317 	 * @deprecated 6.5.0
  1298 	 *
  1318 	 *
  1299 	 * @param string $cropped              Cropped image URL.
  1319 	 * @param string $cropped              Cropped image URL.
  1300 	 * @param int    $parent_attachment_id Attachment ID of parent image.
  1320 	 * @param int    $parent_attachment_id Attachment ID of parent image.
  1301 	 * @return array An array with attachment object data.
  1321 	 * @return array An array with attachment object data.
  1302 	 */
  1322 	 */
  1303 	final public function create_attachment_object( $cropped, $parent_attachment_id ) {
  1323 	final public function create_attachment_object( $cropped, $parent_attachment_id ) {
       
  1324 		_deprecated_function( __METHOD__, '6.5.0', 'wp_copy_parent_attachment_properties()' );
  1304 		$parent     = get_post( $parent_attachment_id );
  1325 		$parent     = get_post( $parent_attachment_id );
  1305 		$parent_url = wp_get_attachment_url( $parent->ID );
  1326 		$parent_url = wp_get_attachment_url( $parent->ID );
  1306 		$url        = str_replace( wp_basename( $parent_url ), wp_basename( $cropped ), $parent_url );
  1327 		$url        = str_replace( wp_basename( $parent_url ), wp_basename( $cropped ), $parent_url );
  1307 
  1328 
  1308 		$size       = wp_getimagesize( $cropped );
  1329 		$size       = wp_getimagesize( $cropped );
  1319 
  1340 
  1320 		return $attachment;
  1341 		return $attachment;
  1321 	}
  1342 	}
  1322 
  1343 
  1323 	/**
  1344 	/**
  1324 	 * Insert an attachment and its metadata.
  1345 	 * Inserts an attachment and its metadata.
  1325 	 *
  1346 	 *
  1326 	 * @since 3.9.0
  1347 	 * @since 3.9.0
  1327 	 *
  1348 	 *
  1328 	 * @param array  $attachment An array with attachment object data.
  1349 	 * @param array  $attachment An array with attachment object data.
  1329 	 * @param string $cropped    File path to cropped image.
  1350 	 * @param string $cropped    File path to cropped image.
  1400 		}
  1421 		}
  1401 
  1422 
  1402 		/** This filter is documented in wp-admin/includes/class-custom-image-header.php */
  1423 		/** This filter is documented in wp-admin/includes/class-custom-image-header.php */
  1403 		$cropped = apply_filters( 'wp_create_file_in_uploads', $cropped, $attachment_id ); // For replication.
  1424 		$cropped = apply_filters( 'wp_create_file_in_uploads', $cropped, $attachment_id ); // For replication.
  1404 
  1425 
  1405 		$attachment = $this->create_attachment_object( $cropped, $attachment_id );
  1426 		$attachment = wp_copy_parent_attachment_properties( $cropped, $attachment_id, 'custom-header' );
  1406 
  1427 
  1407 		$previous = $this->get_previous_crop( $attachment );
  1428 		$previous = $this->get_previous_crop( $attachment );
  1408 
  1429 
  1409 		if ( $previous ) {
  1430 		if ( $previous ) {
  1410 			$attachment['ID'] = $previous;
  1431 			$attachment['ID'] = $previous;
  1569 
  1590 
  1570 		return $header_images;
  1591 		return $header_images;
  1571 	}
  1592 	}
  1572 
  1593 
  1573 	/**
  1594 	/**
  1574 	 * Get the ID of a previous crop from the same base image.
  1595 	 * Gets the ID of a previous crop from the same base image.
  1575 	 *
  1596 	 *
  1576 	 * @since 4.9.0
  1597 	 * @since 4.9.0
  1577 	 *
  1598 	 *
  1578 	 * @param array $attachment An array with a cropped attachment object data.
  1599 	 * @param array $attachment An array with a cropped attachment object data.
  1579 	 * @return int|false An attachment ID if one exists. False if none.
  1600 	 * @return int|false An attachment ID if one exists. False if none.