HEX
Server: Apache
System: Linux mx52.hostgator.mx 5.14.0-687.12.1.el9_8.x86_64 #1 SMP PREEMPT_DYNAMIC Sun Jun 7 14:39:27 EDT 2026 x86_64
User: narrativ (1644)
PHP: 8.2.33
Disabled: NONE
Upload Files
File: /home4/narrativ/public_html/wp-includes/customize/class-wp-customize-header-image-setting.php
<?php
/**
 * Customize API: WP_Customize_Header_Image_Setting class
 *
 * @package WordPress
 * @subpackage Customize
 * @since 4.4.0
 */

/**
 * A setting that is used to filter a value, but will not save the results.
 *
 * Results should be properly handled using another setting or callback.
 *
 * @since 3.4.0
 *
 * @see WP_Customize_Setting
 *
 * @phpstan-type Header_Image_Data array{
 *     attachment_id?: int,
 *     url?: string,
 *     thumbnail_url?: string,
 *     timestamp?: int,
 *     width?: int,
 *     height?: int,
 *     alt_text?: string,
 *     attachment_parent?: int,
 * }
 */
final class WP_Customize_Header_Image_Setting extends WP_Customize_Setting {

	/**
	 * Unique string identifier for the setting.
	 *
	 * @since 3.4.0
	 * @var string
	 */
	public $id = 'header_image_data';

	/**
	 * @since 3.4.0
	 * @since 7.0.0 Return type updated from void to true for compatibility with base class.
	 *
	 * @global Custom_Image_Header $custom_image_header
	 *
	 * @param mixed $value The value to update.
	 * @return true Always returns true.
	 */
	public function update( $value ) {
		global $custom_image_header;

		// If _custom_header_background_just_in_time() fails to initialize $custom_image_header when not is_admin().
		if ( empty( $custom_image_header ) ) {
			require_once ABSPATH . 'wp-admin/includes/class-custom-image-header.php';
			$args                   = get_theme_support( 'custom-header' );
			$admin_head_callback    = $args[0]['admin-head-callback'] ?? null;
			$admin_preview_callback = $args[0]['admin-preview-callback'] ?? null;
			$custom_image_header    = new Custom_Image_Header( $admin_head_callback, $admin_preview_callback );
		}

		/*
		 * If the value doesn't exist (removed or random),
		 * use the header_image value.
		 */
		if ( ! $value ) {
			$value = $this->manager->get_setting( 'header_image' )->post_value();
		}

		if ( is_array( $value ) && isset( $value['choice'] ) ) {
			$custom_image_header->set_header_image( $value['choice'] );
		} else {
			$custom_image_header->set_header_image( $value );
		}
		return true;
	}

	/**
	 * Sanitizes a header value.
	 *
	 * The value is expected to be one of the following:
	 *
	 * - An array of header image data, with the keys `attachment_id`, `url`, `thumbnail_url`, `timestamp`, `width`,
	 *   `height`, `alt_text`, and `attachment_parent`, as supplied by {@see get_uploaded_header_images()}. Any other
	 *   key is discarded.
	 * - An array with a `choice` key, being the legacy format in which any of the other accepted values is nested.
	 * - The string `remove-header`, `random-default-image`, or `random-uploaded-image`.
	 * - A string corresponding to one of the keys for the array returned by {@see get_uploaded_header_images()}, or
	 *   one of the keys for the array passed into {@see register_default_headers()}.
	 *
	 * @since 7.1.1
	 *
	 * @see WP_Customize_Header_Image_Setting::update()
	 * @see Custom_Image_Header::set_header_image()
	 *
	 * @param mixed $value Value to sanitize.
	 * @return array|string|WP_Error|null Sanitized value, or `null`/`WP_Error` if invalid. The array holds
	 *                                    the header image data, or that data nested under a `choice` key,
	 *                                    before the `customize_sanitize_header_image_data` filter, which
	 *                                    may return anything, is applied to it.
	 *
	 * @phpstan-return array<mixed, mixed>|string|WP_Error|null
	 */
	public function sanitize( $value ) {
		/*
		 * The update() method unwraps the legacy `choice` format before handing the value off to
		 * Custom_Image_Header::set_header_image(), so the nested value is what must be sanitized.
		 */
		if ( is_array( $value ) && isset( $value['choice'] ) ) {
			$choice = $this->sanitize_choice( $value['choice'] );
			if ( is_null( $choice ) || is_wp_error( $choice ) ) {
				return $choice;
			}
			$value = array( 'choice' => $choice );
		} else {
			$value = $this->sanitize_choice( $value );
			if ( is_null( $value ) || is_wp_error( $value ) ) {
				return $value;
			}
		}

		return parent::sanitize( $value );
	}

	/**
	 * Sanitizes a header image choice.
	 *
	 * This is the value which is ultimately passed to {@see Custom_Image_Header::set_header_image()}, whether
	 * supplied at the top level of the setting value or nested under its legacy `choice` key.
	 *
	 * @since 7.1.1
	 *
	 * @param mixed $value Value to sanitize.
	 * @return array|string|WP_Error|null Sanitized value, or `null`/`WP_Error` if invalid.
	 *
	 * @phpstan-return Header_Image_Data|string|WP_Error|null
	 */
	private function sanitize_choice( $value ) {
		// Custom_Image_Header::set_header_image() accepts an object in place of an array.
		if ( is_object( $value ) ) {
			$value = (array) $value;
		}

		if ( is_string( $value ) ) {
			return sanitize_text_field( $value );
		}

		if ( ! is_array( $value ) ) {
			return null;
		}

		/*
		 * The sanitized value is assembled member by member rather than filtered down from the
		 * supplied one, so that nothing but the members below can end up in it.
		 */
		$sanitized = array();

		if ( isset( $value['attachment_id'] ) ) {
			if ( ! is_scalar( $value['attachment_id'] ) ) {
				return null;
			}
			$attachment_id = absint( $value['attachment_id'] );

			/*
			 * A supplied attachment must be an existing image, since its ID is written to postmeta and its
			 * data displayed. Note that an ID of zero must be skipped rather than looked up, as
			 * get_post_mime_type() falls back to the global post when passed an empty value.
			 */
			if ( $attachment_id > 0 ) {
				$mime_type = get_post_mime_type( $attachment_id );
				if ( ! is_string( $mime_type ) || ! str_starts_with( $mime_type, 'image/' ) ) {
					return null;
				}
			}

			$sanitized['attachment_id'] = $attachment_id;
		}

		if ( isset( $value['url'] ) ) {
			if ( ! is_string( $value['url'] ) ) {
				return null;
			}
			$sanitized['url'] = sanitize_url( $value['url'] );
			if ( '' === $sanitized['url'] ) {
				return new WP_Error( 'invalid_url', __( 'Invalid URL.' ) );
			}
		}

		if ( isset( $value['thumbnail_url'] ) ) {
			if ( ! is_string( $value['thumbnail_url'] ) ) {
				return null;
			}
			$sanitized['thumbnail_url'] = sanitize_url( $value['thumbnail_url'] );
			if ( '' === $sanitized['thumbnail_url'] ) {
				return new WP_Error( 'invalid_url', __( 'Invalid URL.' ) );
			}
		}

		if ( isset( $value['timestamp'] ) ) {
			if ( ! is_scalar( $value['timestamp'] ) ) {
				return null;
			}
			$sanitized['timestamp'] = absint( $value['timestamp'] );
		}

		if ( isset( $value['width'] ) ) {
			if ( ! is_scalar( $value['width'] ) ) {
				return null;
			}
			$sanitized['width'] = absint( $value['width'] );
		}

		if ( isset( $value['height'] ) ) {
			if ( ! is_scalar( $value['height'] ) ) {
				return null;
			}
			$sanitized['height'] = absint( $value['height'] );
		}

		if ( isset( $value['alt_text'] ) ) {
			if ( ! is_string( $value['alt_text'] ) ) {
				return null;
			}
			$sanitized['alt_text'] = sanitize_text_field( $value['alt_text'] );
		}

		if ( isset( $value['attachment_parent'] ) ) {
			if ( ! is_scalar( $value['attachment_parent'] ) ) {
				return null;
			}
			$sanitized['attachment_parent'] = absint( $value['attachment_parent'] );
		}

		return $sanitized;
	}
}