-
-
+
+
+
+ Customizer.' ),
+ admin_url( 'customize.php?autofocus[control]=header_image' )
+ );
+ ?>
+
-
-
-
+updated ) ) { ?>
+
+
Visit your site to see how it looks.' ), home_url( '/' ) ); ?>
-
-
-
%1$d x %2$d pixels will be used as-is.'), HEADER_IMAGE_WIDTH, HEADER_IMAGE_HEIGHT); ?>
-
-
+
-
+
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
- false);
- $file = wp_handle_upload($_FILES['import'], $overrides);
+ /**
+ * Display second step of custom header image page.
+ *
+ * @since 2.1.0
+ */
+ public function step_2() {
+ check_admin_referer('custom-header-upload', '_wpnonce-custom-header-upload');
+ if ( ! current_theme_supports( 'custom-header', 'uploads' ) )
+ wp_die( __( 'Cheatin’ uh?' ), 403 );
- if ( isset($file['error']) )
- die( $file['error'] );
+ if ( empty( $_POST ) && isset( $_GET['file'] ) ) {
+ $attachment_id = absint( $_GET['file'] );
+ $file = get_attached_file( $attachment_id, true );
+ $url = wp_get_attachment_image_src( $attachment_id, 'full' );
+ $url = $url[0];
+ } elseif ( isset( $_POST ) ) {
+ $data = $this->step_2_manage_upload();
+ $attachment_id = $data['attachment_id'];
+ $file = $data['file'];
+ $url = $data['url'];
+ }
- $url = $file['url'];
- $file = $file['file'];
- $filename = basename($file);
+ if ( file_exists( $file ) ) {
+ list( $width, $height, $type, $attr ) = getimagesize( $file );
+ } else {
+ $data = wp_get_attachment_metadata( $attachment_id );
+ $height = isset( $data[ 'height' ] ) ? $data[ 'height' ] : 0;
+ $width = isset( $data[ 'width' ] ) ? $data[ 'width' ] : 0;
+ unset( $data );
+ }
- // Construct the object array
- $object = array(
- 'post_title' => $filename,
- 'post_content' => $url,
- 'post_mime_type' => 'import',
- 'guid' => $url);
+ $max_width = 0;
+ // For flex, limit size of image displayed to 1500px unless theme says otherwise
+ if ( current_theme_supports( 'custom-header', 'flex-width' ) )
+ $max_width = 1500;
- // Save the data
- $id = wp_insert_attachment($object, $file);
+ if ( current_theme_supports( 'custom-header', 'max-width' ) )
+ $max_width = max( $max_width, get_theme_support( 'custom-header', 'max-width' ) );
+ $max_width = max( $max_width, get_theme_support( 'custom-header', 'width' ) );
+
+ // If flexible height isn't supported and the image is the exact right size
+ if ( ! current_theme_supports( 'custom-header', 'flex-height' ) && ! current_theme_supports( 'custom-header', 'flex-width' )
+ && $width == get_theme_support( 'custom-header', 'width' ) && $height == get_theme_support( 'custom-header', 'height' ) )
+ {
+ // Add the meta-data
+ if ( file_exists( $file ) )
+ wp_update_attachment_metadata( $attachment_id, wp_generate_attachment_metadata( $attachment_id, $file ) );
- $upload = array('file' => $file, 'id' => $id);
+ $this->set_header_image( compact( 'url', 'attachment_id', 'width', 'height' ) );
- list($width, $height, $type, $attr) = getimagesize( $file );
+ /**
+ * Fires after the header image is set or an error is returned.
+ *
+ * @since 2.1.0
+ *
+ * @param string $file Path to the file.
+ * @param int $attachment_id Attachment ID.
+ */
+ do_action( 'wp_create_file_in_uploads', $file, $attachment_id ); // For replication
- if ( $width == HEADER_IMAGE_WIDTH && $height == HEADER_IMAGE_HEIGHT ) {
- set_theme_mod('header_image', clean_url($url));
- $header = apply_filters('wp_create_file_in_uploads', $file, $id); // For replication
return $this->finished();
- } elseif ( $width > HEADER_IMAGE_WIDTH ) {
- $oitar = $width / HEADER_IMAGE_WIDTH;
- $image = wp_crop_image($file, 0, 0, $width, $height, HEADER_IMAGE_WIDTH, $height / $oitar, false, str_replace(basename($file), 'midsize-'.basename($file), $file));
- $image = apply_filters('wp_create_file_in_uploads', $image, $id); // For replication
+ } elseif ( $width > $max_width ) {
+ $oitar = $width / $max_width;
+ $image = wp_crop_image($attachment_id, 0, 0, $width, $height, $max_width, $height / $oitar, false, str_replace(basename($file), 'midsize-'.basename($file), $file));
+ if ( ! $image || is_wp_error( $image ) )
+ wp_die( __( 'Image could not be processed. Please go back and try again.' ), __( 'Image Processing Error' ) );
+
+ /** This filter is documented in wp-admin/custom-header.php */
+ $image = apply_filters( 'wp_create_file_in_uploads', $image, $attachment_id ); // For replication
$url = str_replace(basename($url), basename($image), $url);
$width = $width / $oitar;
@@ -246,34 +755,91 @@ Event.observe( window, 'load', hide_text );
?>
+
-
+
+
+
-
-
-
-
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
false);
+
+ $uploaded_file = $_FILES['import'];
+ $wp_filetype = wp_check_filetype_and_ext( $uploaded_file['tmp_name'], $uploaded_file['name'] );
+ if ( ! wp_match_mime_types( 'image', $wp_filetype['type'] ) )
+ wp_die( __( 'The uploaded file is not a valid image. Please try again.' ) );
+
+ $file = wp_handle_upload($uploaded_file, $overrides);
+
+ if ( isset($file['error']) )
+ wp_die( $file['error'], __( 'Image Upload Error' ) );
+
+ $url = $file['url'];
+ $type = $file['type'];
+ $file = $file['file'];
+ $filename = basename($file);
+
+ // Construct the object array
+ $object = array(
+ 'post_title' => $filename,
+ 'post_content' => $url,
+ 'post_mime_type' => $type,
+ 'guid' => $url,
+ 'context' => 'custom-header'
+ );
+
+ // Save the data
+ $attachment_id = wp_insert_attachment( $object, $file );
+ return compact( 'attachment_id', 'file', 'filename', 'url', 'type' );
+ }
+
+ /**
+ * Display third step of custom header image page.
+ *
+ * @since 2.1.0
+ */
+ public function step_3() {
+ check_admin_referer( 'custom-header-crop-image' );
+
+ if ( ! current_theme_supports( 'custom-header', 'uploads' ) )
+ wp_die( __( 'Cheatin’ uh?' ), 403 );
+
+ if ( ! empty( $_POST['skip-cropping'] ) && ! ( current_theme_supports( 'custom-header', 'flex-height' ) || current_theme_supports( 'custom-header', 'flex-width' ) ) )
+ wp_die( __( 'Cheatin’ uh?' ), 403 );
+
if ( $_POST['oitar'] > 1 ) {
$_POST['x1'] = $_POST['x1'] * $_POST['oitar'];
$_POST['y1'] = $_POST['y1'] * $_POST['oitar'];
@@ -281,52 +847,480 @@ Event.observe( window, 'load', hide_text );
$_POST['height'] = $_POST['height'] * $_POST['oitar'];
}
- $header = wp_crop_image($_POST['attachment_id'], $_POST['x1'], $_POST['y1'], $_POST['width'], $_POST['height'], HEADER_IMAGE_WIDTH, HEADER_IMAGE_HEIGHT);
- $header = apply_filters('wp_create_file_in_uploads', $header); // For replication
+ $attachment_id = absint( $_POST['attachment_id'] );
+ $original = get_attached_file($attachment_id);
- $parent = get_post($_POST['attachment_id']);
+ $dimensions = $this->get_header_dimensions( array(
+ 'height' => $_POST['height'],
+ 'width' => $_POST['width'],
+ ) );
+ $height = $dimensions['dst_height'];
+ $width = $dimensions['dst_width'];
- $parent_url = $parent->guid;
+ if ( empty( $_POST['skip-cropping'] ) )
+ $cropped = wp_crop_image( $attachment_id, (int) $_POST['x1'], (int) $_POST['y1'], (int) $_POST['width'], (int) $_POST['height'], $width, $height );
+ elseif ( ! empty( $_POST['create-new-attachment'] ) )
+ $cropped = _copy_image_file( $attachment_id );
+ else
+ $cropped = get_attached_file( $attachment_id );
- $url = str_replace(basename($parent_url), basename($header), $parent_url);
+ if ( ! $cropped || is_wp_error( $cropped ) )
+ wp_die( __( 'Image could not be processed. Please go back and try again.' ), __( 'Image Processing Error' ) );
- set_theme_mod('header_image', $url);
+ /** This filter is documented in wp-admin/custom-header.php */
+ $cropped = apply_filters( 'wp_create_file_in_uploads', $cropped, $attachment_id ); // For replication
- // cleanup
- $file = get_attached_file( $_POST['attachment_id'] );
- $medium = str_replace(basename($file), 'midsize-'.basename($file), $file);
- @unlink( apply_filters( 'wp_delete_file', $medium ) );
- wp_delete_attachment( $_POST['attachment_id'] );
+ $object = $this->create_attachment_object( $cropped, $attachment_id );
- return $this->finished();
- }
+ if ( ! empty( $_POST['create-new-attachment'] ) )
+ unset( $object['ID'] );
- function finished() {
- ?>
-
-
+ // Update the attachment
+ $attachment_id = $this->insert_attachment( $object, $cropped );
-
+ $url = $object['guid'];
+ $this->set_header_image( compact( 'url', 'attachment_id', 'width', 'height' ) );
-
- finished();
}
- function admin_page() {
- if ( !isset( $_GET['step'] ) )
- $step = 1;
- else
- $step = (int) $_GET['step'];
+ /**
+ * Display last step of custom header image page.
+ *
+ * @since 2.1.0
+ */
+ public function finished() {
+ $this->updated = true;
+ $this->step_1();
+ }
- if ( 1 == $step ) {
- $this->step_1();
- } elseif ( 2 == $step ) {
+ /**
+ * Display the page based on the current step.
+ *
+ * @since 2.1.0
+ */
+ public function admin_page() {
+ if ( ! current_user_can('edit_theme_options') )
+ wp_die(__('You do not have permission to customize headers.'));
+ $step = $this->step();
+ if ( 2 == $step )
$this->step_2();
- } elseif ( 3 == $step ) {
+ elseif ( 3 == $step )
$this->step_3();
+ else
+ $this->step_1();
+ }
+
+ /**
+ * Unused since 3.5.0.
+ *
+ * @since 3.4.0
+ *
+ * @param array $form_fields
+ * @return array $form_fields
+ */
+ public function attachment_fields_to_edit( $form_fields ) {
+ return $form_fields;
+ }
+
+ /**
+ * Unused since 3.5.0.
+ *
+ * @since 3.4.0
+ *
+ * @param array $tabs
+ * @return array $tabs
+ */
+ public function filter_upload_tabs( $tabs ) {
+ return $tabs;
+ }
+
+ /**
+ * Choose a header image, selected from existing uploaded and default headers,
+ * or provide an array of uploaded header data (either new, or from media library).
+ *
+ * @param mixed $choice Which header image to select. Allows for values of 'random-default-image',
+ * for randomly cycling among the default images; 'random-uploaded-image', for randomly cycling
+ * among the uploaded images; the key of a default image registered for that theme; and
+ * the key of an image uploaded for that theme (the basename of the URL).
+ * Or an array of arguments: attachment_id, url, width, height. All are required.
+ *
+ * @since 3.4.0
+ *
+ * @param array|object|string $choice
+ */
+ final public function set_header_image( $choice ) {
+ if ( is_array( $choice ) || is_object( $choice ) ) {
+ $choice = (array) $choice;
+ if ( ! isset( $choice['attachment_id'] ) || ! isset( $choice['url'] ) )
+ return;
+
+ $choice['url'] = esc_url_raw( $choice['url'] );
+
+ $header_image_data = (object) array(
+ 'attachment_id' => $choice['attachment_id'],
+ 'url' => $choice['url'],
+ 'thumbnail_url' => $choice['url'],
+ 'height' => $choice['height'],
+ 'width' => $choice['width'],
+ );
+
+ update_post_meta( $choice['attachment_id'], '_wp_attachment_is_custom_header', get_stylesheet() );
+ set_theme_mod( 'header_image', $choice['url'] );
+ set_theme_mod( 'header_image_data', $header_image_data );
+ return;
+ }
+
+ if ( in_array( $choice, array( 'remove-header', 'random-default-image', 'random-uploaded-image' ) ) ) {
+ set_theme_mod( 'header_image', $choice );
+ remove_theme_mod( 'header_image_data' );
+ return;
+ }
+
+ $uploaded = get_uploaded_header_images();
+ if ( $uploaded && isset( $uploaded[ $choice ] ) ) {
+ $header_image_data = $uploaded[ $choice ];
+
+ } else {
+ $this->process_default_headers();
+ if ( isset( $this->default_headers[ $choice ] ) )
+ $header_image_data = $this->default_headers[ $choice ];
+ else
+ return;
}
+ set_theme_mod( 'header_image', esc_url_raw( $header_image_data['url'] ) );
+ set_theme_mod( 'header_image_data', $header_image_data );
}
+ /**
+ * Remove a header image.
+ *
+ * @since 3.4.0
+ */
+ final public function remove_header_image() {
+ $this->set_header_image( 'remove-header' );
+ }
+
+ /**
+ * Reset a header image to the default image for the theme.
+ *
+ * This method does not do anything if the theme does not have a default header image.
+ *
+ * @since 3.4.0
+ */
+ final public function reset_header_image() {
+ $this->process_default_headers();
+ $default = get_theme_support( 'custom-header', 'default-image' );
+
+ if ( ! $default ) {
+ $this->remove_header_image();
+ return;
+ }
+ $default = sprintf( $default, get_template_directory_uri(), get_stylesheet_directory_uri() );
+
+ $default_data = array();
+ foreach ( $this->default_headers as $header => $details ) {
+ if ( $details['url'] == $default ) {
+ $default_data = $details;
+ break;
+ }
+ }
+
+ set_theme_mod( 'header_image', $default );
+ set_theme_mod( 'header_image_data', (object) $default_data );
+ }
+
+ /**
+ * Calculate width and height based on what the currently selected theme supports.
+ *
+ * @param array $dimensions
+ * @return array dst_height and dst_width of header image.
+ */
+ final public function get_header_dimensions( $dimensions ) {
+ $max_width = 0;
+ $width = absint( $dimensions['width'] );
+ $height = absint( $dimensions['height'] );
+ $theme_height = get_theme_support( 'custom-header', 'height' );
+ $theme_width = get_theme_support( 'custom-header', 'width' );
+ $has_flex_width = current_theme_supports( 'custom-header', 'flex-width' );
+ $has_flex_height = current_theme_supports( 'custom-header', 'flex-height' );
+ $has_max_width = current_theme_supports( 'custom-header', 'max-width' ) ;
+ $dst = array( 'dst_height' => null, 'dst_width' => null );
+
+ // For flex, limit size of image displayed to 1500px unless theme says otherwise
+ if ( $has_flex_width ) {
+ $max_width = 1500;
+ }
+
+ if ( $has_max_width ) {
+ $max_width = max( $max_width, get_theme_support( 'custom-header', 'max-width' ) );
+ }
+ $max_width = max( $max_width, $theme_width );
+
+ if ( $has_flex_height && ( ! $has_flex_width || $width > $max_width ) ) {
+ $dst['dst_height'] = absint( $height * ( $max_width / $width ) );
+ }
+ elseif ( $has_flex_height && $has_flex_width ) {
+ $dst['dst_height'] = $height;
+ }
+ else {
+ $dst['dst_height'] = $theme_height;
+ }
+
+ if ( $has_flex_width && ( ! $has_flex_height || $width > $max_width ) ) {
+ $dst['dst_width'] = absint( $width * ( $max_width / $width ) );
+ }
+ elseif ( $has_flex_width && $has_flex_height ) {
+ $dst['dst_width'] = $width;
+ }
+ else {
+ $dst['dst_width'] = $theme_width;
+ }
+
+ return $dst;
+ }
+
+ /**
+ * Create an attachment 'object'.
+ *
+ * @param string $cropped Cropped image URL.
+ * @param int $parent_attachment_id Attachment ID of parent image.
+ *
+ * @return array Attachment object.
+ */
+ final public function create_attachment_object( $cropped, $parent_attachment_id ) {
+ $parent = get_post( $parent_attachment_id );
+ $parent_url = $parent->guid;
+ $url = str_replace( basename( $parent_url ), basename( $cropped ), $parent_url );
+
+ $size = @getimagesize( $cropped );
+ $image_type = ( $size ) ? $size['mime'] : 'image/jpeg';
+
+ $object = array(
+ 'ID' => $parent_attachment_id,
+ 'post_title' => basename($cropped),
+ 'post_content' => $url,
+ 'post_mime_type' => $image_type,
+ 'guid' => $url,
+ 'context' => 'custom-header'
+ );
+
+ return $object;
+ }
+
+ /**
+ * Insert an attachment and its metadata.
+ *
+ * @param array $object Attachment object.
+ * @param string $cropped Cropped image URL.
+ *
+ * @return int Attachment ID.
+ */
+ final public function insert_attachment( $object, $cropped ) {
+ $attachment_id = wp_insert_attachment( $object, $cropped );
+ $metadata = wp_generate_attachment_metadata( $attachment_id, $cropped );
+ /**
+ * Filter the header image attachment metadata.
+ *
+ * @since 3.9.0
+ *
+ * @see wp_generate_attachment_metadata()
+ *
+ * @param array $metadata Attachment metadata.
+ */
+ $metadata = apply_filters( 'wp_header_image_attachment_metadata', $metadata );
+ wp_update_attachment_metadata( $attachment_id, $metadata );
+ return $attachment_id;
+ }
+
+ /**
+ * Gets attachment uploaded by Media Manager, crops it, then saves it as a
+ * new object. Returns JSON-encoded object details.
+ */
+ public function ajax_header_crop() {
+ check_ajax_referer( 'image_editor-' . $_POST['id'], 'nonce' );
+
+ if ( ! current_user_can( 'edit_theme_options' ) ) {
+ wp_send_json_error();
+ }
+
+ if ( ! current_theme_supports( 'custom-header', 'uploads' ) ) {
+ wp_send_json_error();
+ }
+
+ $crop_details = $_POST['cropDetails'];
+
+ $dimensions = $this->get_header_dimensions( array(
+ 'height' => $crop_details['height'],
+ 'width' => $crop_details['width'],
+ ) );
+
+ $attachment_id = absint( $_POST['id'] );
+
+ $cropped = wp_crop_image(
+ $attachment_id,
+ (int) $crop_details['x1'],
+ (int) $crop_details['y1'],
+ (int) $crop_details['width'],
+ (int) $crop_details['height'],
+ (int) $dimensions['dst_width'],
+ (int) $dimensions['dst_height']
+ );
+
+ if ( ! $cropped || is_wp_error( $cropped ) ) {
+ wp_send_json_error( array( 'message' => __( 'Image could not be processed. Please go back and try again.' ) ) );
+ }
+
+ /** This filter is documented in wp-admin/custom-header.php */
+ $cropped = apply_filters( 'wp_create_file_in_uploads', $cropped, $attachment_id ); // For replication
+
+ $object = $this->create_attachment_object( $cropped, $attachment_id );
+
+ unset( $object['ID'] );
+
+ $new_attachment_id = $this->insert_attachment( $object, $cropped );
+
+ $object['attachment_id'] = $new_attachment_id;
+ $object['width'] = $dimensions['dst_width'];
+ $object['height'] = $dimensions['dst_height'];
+
+ wp_send_json_success( $object );
+ }
+
+ /**
+ * Given an attachment ID for a header image, updates its "last used"
+ * timestamp to now.
+ *
+ * Triggered when the user tries adds a new header image from the
+ * Media Manager, even if s/he doesn't save that change.
+ */
+ public function ajax_header_add() {
+ check_ajax_referer( 'header-add', 'nonce' );
+
+ if ( ! current_user_can( 'edit_theme_options' ) ) {
+ wp_send_json_error();
+ }
+
+ $attachment_id = absint( $_POST['attachment_id'] );
+ if ( $attachment_id < 1 ) {
+ wp_send_json_error();
+ }
+
+ $key = '_wp_attachment_custom_header_last_used_' . get_stylesheet();
+ update_post_meta( $attachment_id, $key, time() );
+ update_post_meta( $attachment_id, '_wp_attachment_is_custom_header', get_stylesheet() );
+
+ wp_send_json_success();
+ }
+
+ /**
+ * Given an attachment ID for a header image, unsets it as a user-uploaded
+ * header image for the current theme.
+ *
+ * Triggered when the user clicks the overlay "X" button next to each image
+ * choice in the Customizer's Header tool.
+ */
+ public function ajax_header_remove() {
+ check_ajax_referer( 'header-remove', 'nonce' );
+
+ if ( ! current_user_can( 'edit_theme_options' ) ) {
+ wp_send_json_error();
+ }
+
+ $attachment_id = absint( $_POST['attachment_id'] );
+ if ( $attachment_id < 1 ) {
+ wp_send_json_error();
+ }
+
+ $key = '_wp_attachment_custom_header_last_used_' . get_stylesheet();
+ delete_post_meta( $attachment_id, $key );
+ delete_post_meta( $attachment_id, '_wp_attachment_is_custom_header', get_stylesheet() );
+
+ wp_send_json_success();
+ }
+
+ /**
+ *
+ * @param WP_Customize_Manager $wp_customize
+ */
+ public function customize_set_last_used( $wp_customize ) {
+ $data = $wp_customize->get_setting( 'header_image_data' )->post_value();
+
+ if ( ! isset( $data['attachment_id'] ) ) {
+ return;
+ }
+
+ $attachment_id = $data['attachment_id'];
+ $key = '_wp_attachment_custom_header_last_used_' . get_stylesheet();
+ update_post_meta( $attachment_id, $key, time() );
+ }
+
+ /**
+ *
+ * @return array
+ */
+ public function get_default_header_images() {
+ $this->process_default_headers();
+
+ // Get the default image if there is one.
+ $default = get_theme_support( 'custom-header', 'default-image' );
+
+ if ( ! $default ) { // If not,
+ return $this->default_headers; // easy peasy.
+ }
+
+ $default = sprintf( $default, get_template_directory_uri(), get_stylesheet_directory_uri() );
+ $already_has_default = false;
+
+ foreach ( $this->default_headers as $k => $h ) {
+ if ( $h['url'] === $default ) {
+ $already_has_default = true;
+ break;
+ }
+ }
+
+ if ( $already_has_default ) {
+ return $this->default_headers;
+ }
+
+ // If the one true image isn't included in the default set, prepend it.
+ $header_images = array();
+ $header_images['default'] = array(
+ 'url' => $default,
+ 'thumbnail_url' => $default,
+ 'description' => 'Default'
+ );
+
+ // The rest of the set comes after.
+ return array_merge( $header_images, $this->default_headers );
+ }
+
+ /**
+ *
+ * @return array
+ */
+ public function get_uploaded_header_images() {
+ $header_images = get_uploaded_header_images();
+ $timestamp_key = '_wp_attachment_custom_header_last_used_' . get_stylesheet();
+ $alt_text_key = '_wp_attachment_image_alt';
+
+ foreach ( $header_images as &$header_image ) {
+ $header_meta = get_post_meta( $header_image['attachment_id'] );
+ $header_image['timestamp'] = isset( $header_meta[ $timestamp_key ] ) ? $header_meta[ $timestamp_key ] : '';
+ $header_image['alt_text'] = isset( $header_meta[ $alt_text_key ] ) ? $header_meta[ $alt_text_key ] : '';
+ }
+
+ return $header_images;
+ }
}
-?>