wp/wp-includes/class-wp-customize-manager.php
changeset 21 48c4eec2b7e6
parent 19 3d72ae0968f4
child 22 8c2e4d02f4ef
equal deleted inserted replaced
20:7b1b88e27a20 21:48c4eec2b7e6
    18  * Serves as a factory for Customize Controls and Settings, and
    18  * Serves as a factory for Customize Controls and Settings, and
    19  * instantiates default Customize Controls and Settings.
    19  * instantiates default Customize Controls and Settings.
    20  *
    20  *
    21  * @since 3.4.0
    21  * @since 3.4.0
    22  */
    22  */
       
    23 #[AllowDynamicProperties]
    23 final class WP_Customize_Manager {
    24 final class WP_Customize_Manager {
    24 	/**
    25 	/**
    25 	 * An instance of the theme being previewed.
    26 	 * An instance of the theme being previewed.
    26 	 *
    27 	 *
    27 	 * @since 3.4.0
    28 	 * @since 3.4.0
    97 	 * List of core components.
    98 	 * List of core components.
    98 	 *
    99 	 *
    99 	 * @since 4.5.0
   100 	 * @since 4.5.0
   100 	 * @var array
   101 	 * @var array
   101 	 */
   102 	 */
   102 	protected $components = array( 'widgets', 'nav_menus' );
   103 	protected $components = array( 'nav_menus' );
   103 
   104 
   104 	/**
   105 	/**
   105 	 * Registered instances of WP_Customize_Section.
   106 	 * Registered instances of WP_Customize_Section.
   106 	 *
   107 	 *
   107 	 * @since 3.4.0
   108 	 * @since 3.4.0
   268 		// Note that the UUID format will be validated in the setup_theme() method.
   269 		// Note that the UUID format will be validated in the setup_theme() method.
   269 		if ( ! isset( $args['changeset_uuid'] ) ) {
   270 		if ( ! isset( $args['changeset_uuid'] ) ) {
   270 			$args['changeset_uuid'] = wp_generate_uuid4();
   271 			$args['changeset_uuid'] = wp_generate_uuid4();
   271 		}
   272 		}
   272 
   273 
   273 		// The theme and messenger_channel should be supplied via $args,
   274 		/*
   274 		// but they are also looked at in the $_REQUEST global here for back-compat.
   275 		 * The theme and messenger_channel should be supplied via $args,
       
   276 		 * but they are also looked at in the $_REQUEST global here for back-compat.
       
   277 		 */
   275 		if ( ! isset( $args['theme'] ) ) {
   278 		if ( ! isset( $args['theme'] ) ) {
   276 			if ( isset( $_REQUEST['customize_theme'] ) ) {
   279 			if ( isset( $_REQUEST['customize_theme'] ) ) {
   277 				$args['theme'] = wp_unslash( $_REQUEST['customize_theme'] );
   280 				$args['theme'] = wp_unslash( $_REQUEST['customize_theme'] );
   278 			} elseif ( isset( $_REQUEST['theme'] ) ) { // Deprecated.
   281 			} elseif ( isset( $_REQUEST['theme'] ) ) { // Deprecated.
   279 				$args['theme'] = wp_unslash( $_REQUEST['theme'] );
   282 				$args['theme'] = wp_unslash( $_REQUEST['theme'] );
   280 			}
   283 			}
   281 		}
   284 		}
   282 		if ( ! isset( $args['messenger_channel'] ) && isset( $_REQUEST['customize_messenger_channel'] ) ) {
   285 		if ( ! isset( $args['messenger_channel'] ) && isset( $_REQUEST['customize_messenger_channel'] ) ) {
   283 			$args['messenger_channel'] = sanitize_key( wp_unslash( $_REQUEST['customize_messenger_channel'] ) );
   286 			$args['messenger_channel'] = sanitize_key( wp_unslash( $_REQUEST['customize_messenger_channel'] ) );
       
   287 		}
       
   288 
       
   289 		// Do not load 'widgets' component if a block theme is activated.
       
   290 		if ( ! wp_is_block_theme() ) {
       
   291 			$this->components[] = 'widgets';
   284 		}
   292 		}
   285 
   293 
   286 		$this->original_stylesheet = get_stylesheet();
   294 		$this->original_stylesheet = get_stylesheet();
   287 		$this->theme               = wp_get_theme( 0 === validate_file( $args['theme'] ) ? $args['theme'] : null );
   295 		$this->theme               = wp_get_theme( 0 === validate_file( $args['theme'] ) ? $args['theme'] : null );
   288 		$this->messenger_channel   = $args['messenger_channel'];
   296 		$this->messenger_channel   = $args['messenger_channel'];
   459 					'channel' => $this->messenger_channel,
   467 					'channel' => $this->messenger_channel,
   460 					'url'     => wp_customize_url(),
   468 					'url'     => wp_customize_url(),
   461 				),
   469 				),
   462 				'error'         => $ajax_message,
   470 				'error'         => $ajax_message,
   463 			);
   471 			);
       
   472 			$message .= ob_get_clean();
       
   473 			ob_start();
   464 			?>
   474 			?>
   465 			<script>
   475 			<script>
   466 			( function( api, settings ) {
   476 			( function( api, settings ) {
   467 				var preview = new api.Messenger( settings.messengerArgs );
   477 				var preview = new api.Messenger( settings.messengerArgs );
   468 				preview.send( 'iframe-loading-error', settings.error );
   478 				preview.send( 'iframe-loading-error', settings.error );
   469 			} )( wp.customize, <?php echo wp_json_encode( $settings ); ?> );
   479 			} )( wp.customize, <?php echo wp_json_encode( $settings ); ?> );
   470 			</script>
   480 			</script>
   471 			<?php
   481 			<?php
   472 			$message .= ob_get_clean();
   482 			$message .= wp_get_inline_script_tag( wp_remove_surrounding_empty_script_tags( ob_get_clean() ) );
   473 		}
   483 		}
   474 
   484 
   475 		wp_die( $message );
   485 		wp_die( $message );
   476 	}
   486 	}
   477 
   487 
   562 
   572 
   563 		if ( $this->is_theme_active() ) {
   573 		if ( $this->is_theme_active() ) {
   564 			// Once the theme is loaded, we'll validate it.
   574 			// Once the theme is loaded, we'll validate it.
   565 			add_action( 'after_setup_theme', array( $this, 'after_setup_theme' ) );
   575 			add_action( 'after_setup_theme', array( $this, 'after_setup_theme' ) );
   566 		} else {
   576 		} else {
   567 			// If the requested theme is not the active theme and the user doesn't have
   577 			/*
   568 			// the switch_themes cap, bail.
   578 			 * If the requested theme is not the active theme and the user doesn't have
       
   579 			 * the switch_themes cap, bail.
       
   580 			 */
   569 			if ( ! current_user_can( 'switch_themes' ) ) {
   581 			if ( ! current_user_can( 'switch_themes' ) ) {
   570 				$this->wp_die( -1, __( 'Sorry, you are not allowed to edit theme options on this site.' ) );
   582 				$this->wp_die( -1, __( 'Sorry, you are not allowed to edit theme options on this site.' ) );
   571 			}
   583 			}
   572 
   584 
   573 			// If the theme has errors while loading, bail.
   585 			// If the theme has errors while loading, bail.
   902 	 *
   914 	 *
   903 	 * @since 3.4.0
   915 	 * @since 3.4.0
   904 	 */
   916 	 */
   905 	public function wp_loaded() {
   917 	public function wp_loaded() {
   906 
   918 
   907 		// Unconditionally register core types for panels, sections, and controls
   919 		/*
   908 		// in case plugin unhooks all customize_register actions.
   920 		 * Unconditionally register core types for panels, sections, and controls
       
   921 		 * in case plugin unhooks all customize_register actions.
       
   922 		 */
   909 		$this->register_panel_type( 'WP_Customize_Panel' );
   923 		$this->register_panel_type( 'WP_Customize_Panel' );
   910 		$this->register_panel_type( 'WP_Customize_Themes_Panel' );
   924 		$this->register_panel_type( 'WP_Customize_Themes_Panel' );
   911 		$this->register_section_type( 'WP_Customize_Section' );
   925 		$this->register_section_type( 'WP_Customize_Section' );
   912 		$this->register_section_type( 'WP_Customize_Sidebar_Section' );
   926 		$this->register_section_type( 'WP_Customize_Sidebar_Section' );
   913 		$this->register_section_type( 'WP_Customize_Themes_Section' );
   927 		$this->register_section_type( 'WP_Customize_Themes_Section' );
  1068 		foreach ( $changeset_autodraft_posts as $autosave_autodraft_post ) {
  1082 		foreach ( $changeset_autodraft_posts as $autosave_autodraft_post ) {
  1069 			if ( $autosave_autodraft_post->ID === $this->changeset_post_id() ) {
  1083 			if ( $autosave_autodraft_post->ID === $this->changeset_post_id() ) {
  1070 				continue;
  1084 				continue;
  1071 			}
  1085 			}
  1072 			if ( update_post_meta( $autosave_autodraft_post->ID, '_customize_restore_dismissed', true ) ) {
  1086 			if ( update_post_meta( $autosave_autodraft_post->ID, '_customize_restore_dismissed', true ) ) {
  1073 				$dismissed++;
  1087 				++$dismissed;
  1074 			}
  1088 			}
  1075 		}
  1089 		}
  1076 		return $dismissed;
  1090 		return $dismissed;
  1077 	}
  1091 	}
  1078 
  1092 
  1470 				}
  1484 				}
  1471 			}
  1485 			}
  1472 
  1486 
  1473 			if ( ! $nav_menu_term_id ) {
  1487 			if ( ! $nav_menu_term_id ) {
  1474 				while ( isset( $changeset_data[ sprintf( 'nav_menu[%d]', $placeholder_id ) ] ) ) {
  1488 				while ( isset( $changeset_data[ sprintf( 'nav_menu[%d]', $placeholder_id ) ] ) ) {
  1475 					$placeholder_id--;
  1489 					--$placeholder_id;
  1476 				}
  1490 				}
  1477 				$nav_menu_term_id    = $placeholder_id;
  1491 				$nav_menu_term_id    = $placeholder_id;
  1478 				$nav_menu_setting_id = sprintf( 'nav_menu[%d]', $placeholder_id );
  1492 				$nav_menu_setting_id = sprintf( 'nav_menu[%d]', $placeholder_id );
  1479 			}
  1493 			}
  1480 
  1494 
  1900 		 * not send no-cache headers by default.
  1914 		 * not send no-cache headers by default.
  1901 		 */
  1915 		 */
  1902 		if ( ! headers_sent() ) {
  1916 		if ( ! headers_sent() ) {
  1903 			nocache_headers();
  1917 			nocache_headers();
  1904 			header( 'X-Robots: noindex, nofollow, noarchive' );
  1918 			header( 'X-Robots: noindex, nofollow, noarchive' );
       
  1919 			header( 'X-Robots-Tag: noindex, nofollow, noarchive' );
  1905 		}
  1920 		}
  1906 		add_filter( 'wp_robots', 'wp_robots_no_robots' );
  1921 		add_filter( 'wp_robots', 'wp_robots_no_robots' );
  1907 		add_filter( 'wp_headers', array( $this, 'filter_iframe_security_headers' ) );
  1922 		add_filter( 'wp_headers', array( $this, 'filter_iframe_security_headers' ) );
  1908 
  1923 
  1909 		/*
  1924 		/*
  1978 			$is_allowed         = (
  1993 			$is_allowed         = (
  1979 				$parsed_allowed_url['scheme'] === $parsed_original_url['scheme']
  1994 				$parsed_allowed_url['scheme'] === $parsed_original_url['scheme']
  1980 				&&
  1995 				&&
  1981 				$parsed_allowed_url['host'] === $parsed_original_url['host']
  1996 				$parsed_allowed_url['host'] === $parsed_original_url['host']
  1982 				&&
  1997 				&&
  1983 				0 === strpos( $parsed_original_url['path'], $parsed_allowed_url['path'] )
  1998 				str_starts_with( $parsed_original_url['path'], $parsed_allowed_url['path'] )
  1984 			);
  1999 			);
  1985 			if ( $is_allowed ) {
  2000 			if ( $is_allowed ) {
  1986 				break;
  2001 				break;
  1987 			}
  2002 			}
  1988 		}
  2003 		}
  2073 	 */
  2088 	 */
  2074 	public function remove_frameless_preview_messenger_channel() {
  2089 	public function remove_frameless_preview_messenger_channel() {
  2075 		if ( ! $this->messenger_channel ) {
  2090 		if ( ! $this->messenger_channel ) {
  2076 			return;
  2091 			return;
  2077 		}
  2092 		}
       
  2093 		ob_start();
  2078 		?>
  2094 		?>
  2079 		<script>
  2095 		<script>
  2080 		( function() {
  2096 		( function() {
  2081 			var urlParser, oldQueryParams, newQueryParams, i;
       
  2082 			if ( parent !== window ) {
  2097 			if ( parent !== window ) {
  2083 				return;
  2098 				return;
  2084 			}
  2099 			}
  2085 			urlParser = document.createElement( 'a' );
  2100 			const url = new URL( location.href );
  2086 			urlParser.href = location.href;
  2101 			if ( url.searchParams.has( 'customize_messenger_channel' ) ) {
  2087 			oldQueryParams = urlParser.search.substr( 1 ).split( /&/ );
  2102 				url.searchParams.delete( 'customize_messenger_channel' );
  2088 			newQueryParams = [];
  2103 				location.replace( url );
  2089 			for ( i = 0; i < oldQueryParams.length; i += 1 ) {
       
  2090 				if ( ! /^customize_messenger_channel=/.test( oldQueryParams[ i ] ) ) {
       
  2091 					newQueryParams.push( oldQueryParams[ i ] );
       
  2092 				}
       
  2093 			}
       
  2094 			urlParser.search = newQueryParams.join( '&' );
       
  2095 			if ( urlParser.search !== location.search ) {
       
  2096 				location.replace( urlParser.href );
       
  2097 			}
  2104 			}
  2098 		} )();
  2105 		} )();
  2099 		</script>
  2106 		</script>
  2100 		<?php
  2107 		<?php
       
  2108 		wp_print_inline_script_tag( wp_remove_surrounding_empty_script_tags( ob_get_clean() ) );
  2101 	}
  2109 	}
  2102 
  2110 
  2103 	/**
  2111 	/**
  2104 	 * Prints JavaScript settings for preview frame.
  2112 	 * Prints JavaScript settings for preview frame.
  2105 	 *
  2113 	 *
  2109 		$post_values                 = $this->unsanitized_post_values( array( 'exclude_changeset' => true ) );
  2117 		$post_values                 = $this->unsanitized_post_values( array( 'exclude_changeset' => true ) );
  2110 		$setting_validities          = $this->validate_setting_values( $post_values );
  2118 		$setting_validities          = $this->validate_setting_values( $post_values );
  2111 		$exported_setting_validities = array_map( array( $this, 'prepare_setting_validity_for_js' ), $setting_validities );
  2119 		$exported_setting_validities = array_map( array( $this, 'prepare_setting_validity_for_js' ), $setting_validities );
  2112 
  2120 
  2113 		// Note that the REQUEST_URI is not passed into home_url() since this breaks subdirectory installations.
  2121 		// Note that the REQUEST_URI is not passed into home_url() since this breaks subdirectory installations.
  2114 		$self_url           = empty( $_SERVER['REQUEST_URI'] ) ? home_url( '/' ) : esc_url_raw( wp_unslash( $_SERVER['REQUEST_URI'] ) );
  2122 		$self_url           = empty( $_SERVER['REQUEST_URI'] ) ? home_url( '/' ) : sanitize_url( wp_unslash( $_SERVER['REQUEST_URI'] ) );
  2115 		$state_query_params = array(
  2123 		$state_query_params = array(
  2116 			'customize_theme',
  2124 			'customize_theme',
  2117 			'customize_changeset_uuid',
  2125 			'customize_changeset_uuid',
  2118 			'customize_messenger_channel',
  2126 			'customize_messenger_channel',
  2119 		);
  2127 		);
  2131 				$host .= ':' . $parsed['port'];
  2139 				$host .= ':' . $parsed['port'];
  2132 			}
  2140 			}
  2133 			$allowed_hosts[] = $host;
  2141 			$allowed_hosts[] = $host;
  2134 		}
  2142 		}
  2135 
  2143 
  2136 		$switched_locale = switch_to_locale( get_user_locale() );
  2144 		$switched_locale = switch_to_user_locale( get_current_user_id() );
  2137 		$l10n            = array(
  2145 		$l10n            = array(
  2138 			'shiftClickToEdit'  => __( 'Shift-click to edit this element.' ),
  2146 			'shiftClickToEdit'  => __( 'Shift-click to edit this element.' ),
  2139 			'linkUnpreviewable' => __( 'This link is not live-previewable.' ),
  2147 			'linkUnpreviewable' => __( 'This link is not live-previewable.' ),
  2140 			'formUnpreviewable' => __( 'This form is not live-previewable.' ),
  2148 			'formUnpreviewable' => __( 'This form is not live-previewable.' ),
  2141 		);
  2149 		);
  2156 				'stylesheet' => $this->get_stylesheet(),
  2164 				'stylesheet' => $this->get_stylesheet(),
  2157 				'active'     => $this->is_theme_active(),
  2165 				'active'     => $this->is_theme_active(),
  2158 			),
  2166 			),
  2159 			'url'               => array(
  2167 			'url'               => array(
  2160 				'self'          => $self_url,
  2168 				'self'          => $self_url,
  2161 				'allowed'       => array_map( 'esc_url_raw', $this->get_allowed_urls() ),
  2169 				'allowed'       => array_map( 'sanitize_url', $this->get_allowed_urls() ),
  2162 				'allowedHosts'  => array_unique( $allowed_hosts ),
  2170 				'allowedHosts'  => array_unique( $allowed_hosts ),
  2163 				'isCrossDomain' => $this->is_cross_domain(),
  2171 				'isCrossDomain' => $this->is_cross_domain(),
  2164 			),
  2172 			),
  2165 			'channel'           => $this->messenger_channel,
  2173 			'channel'           => $this->messenger_channel,
  2166 			'activePanels'      => array(),
  2174 			'activePanels'      => array(),
  2191 			if ( $control->check_capabilities() ) {
  2199 			if ( $control->check_capabilities() ) {
  2192 				$settings['activeControls'][ $id ] = $control->active();
  2200 				$settings['activeControls'][ $id ] = $control->active();
  2193 			}
  2201 			}
  2194 		}
  2202 		}
  2195 
  2203 
       
  2204 		ob_start();
  2196 		?>
  2205 		?>
  2197 		<script type="text/javascript">
  2206 		<script>
  2198 			var _wpCustomizeSettings = <?php echo wp_json_encode( $settings ); ?>;
  2207 			var _wpCustomizeSettings = <?php echo wp_json_encode( $settings ); ?>;
  2199 			_wpCustomizeSettings.values = {};
  2208 			_wpCustomizeSettings.values = {};
  2200 			(function( v ) {
  2209 			(function( v ) {
  2201 				<?php
  2210 				<?php
  2202 				/*
  2211 				/*
  2215 				}
  2224 				}
  2216 				?>
  2225 				?>
  2217 			})( _wpCustomizeSettings.values );
  2226 			})( _wpCustomizeSettings.values );
  2218 		</script>
  2227 		</script>
  2219 		<?php
  2228 		<?php
       
  2229 		wp_print_inline_script_tag( wp_remove_surrounding_empty_script_tags( ob_get_clean() ) );
  2220 	}
  2230 	}
  2221 
  2231 
  2222 	/**
  2232 	/**
  2223 	 * Prints a signature so we can ensure the Customizer was properly executed.
  2233 	 * Prints a signature so we can ensure the Customizer was properly executed.
  2224 	 *
  2234 	 *
  3072 
  3082 
  3073 		if ( 'trash' === get_post_status( $post ) ) {
  3083 		if ( 'trash' === get_post_status( $post ) ) {
  3074 			return false;
  3084 			return false;
  3075 		}
  3085 		}
  3076 
  3086 
       
  3087 		$previous_status = $post->post_status;
       
  3088 
  3077 		/** This filter is documented in wp-includes/post.php */
  3089 		/** This filter is documented in wp-includes/post.php */
  3078 		$check = apply_filters( 'pre_trash_post', null, $post );
  3090 		$check = apply_filters( 'pre_trash_post', null, $post, $previous_status );
  3079 		if ( null !== $check ) {
  3091 		if ( null !== $check ) {
  3080 			return $check;
  3092 			return $check;
  3081 		}
  3093 		}
  3082 
  3094 
  3083 		/** This action is documented in wp-includes/post.php */
  3095 		/** This action is documented in wp-includes/post.php */
  3084 		do_action( 'wp_trash_post', $post_id );
  3096 		do_action( 'wp_trash_post', $post_id, $previous_status );
  3085 
  3097 
  3086 		add_post_meta( $post_id, '_wp_trash_meta_status', $post->post_status );
  3098 		add_post_meta( $post_id, '_wp_trash_meta_status', $previous_status );
  3087 		add_post_meta( $post_id, '_wp_trash_meta_time', time() );
  3099 		add_post_meta( $post_id, '_wp_trash_meta_time', time() );
  3088 
  3100 
  3089 		$old_status = $post->post_status;
       
  3090 		$new_status = 'trash';
  3101 		$new_status = 'trash';
  3091 		$wpdb->update( $wpdb->posts, array( 'post_status' => $new_status ), array( 'ID' => $post->ID ) );
  3102 		$wpdb->update( $wpdb->posts, array( 'post_status' => $new_status ), array( 'ID' => $post->ID ) );
  3092 		clean_post_cache( $post->ID );
  3103 		clean_post_cache( $post->ID );
  3093 
  3104 
  3094 		$post->post_status = $new_status;
  3105 		$post->post_status = $new_status;
  3095 		wp_transition_post_status( $new_status, $old_status, $post );
  3106 		wp_transition_post_status( $new_status, $previous_status, $post );
  3096 
  3107 
  3097 		/** This action is documented in wp-includes/post.php */
  3108 		/** This action is documented in wp-includes/post.php */
  3098 		do_action( "edit_post_{$post->post_type}", $post->ID, $post );
  3109 		do_action( "edit_post_{$post->post_type}", $post->ID, $post );
  3099 
  3110 
  3100 		/** This action is documented in wp-includes/post.php */
  3111 		/** This action is documented in wp-includes/post.php */
  3112 		wp_after_insert_post( get_post( $post_id ), true, $post );
  3123 		wp_after_insert_post( get_post( $post_id ), true, $post );
  3113 
  3124 
  3114 		wp_trash_post_comments( $post_id );
  3125 		wp_trash_post_comments( $post_id );
  3115 
  3126 
  3116 		/** This action is documented in wp-includes/post.php */
  3127 		/** This action is documented in wp-includes/post.php */
  3117 		do_action( 'trashed_post', $post_id );
  3128 		do_action( 'trashed_post', $post_id, $previous_status );
  3118 
  3129 
  3119 		return $post;
  3130 		return $post;
  3120 	}
  3131 	}
  3121 
  3132 
  3122 	/**
  3133 	/**
  3425 	 * Note that this will not be called while a changeset post remains in auto-draft status.
  3436 	 * Note that this will not be called while a changeset post remains in auto-draft status.
  3426 	 *
  3437 	 *
  3427 	 * @since 4.7.0
  3438 	 * @since 4.7.0
  3428 	 *
  3439 	 *
  3429 	 * @param bool    $post_has_changed Whether the post has changed.
  3440 	 * @param bool    $post_has_changed Whether the post has changed.
  3430 	 * @param WP_Post $last_revision    The last revision post object.
  3441 	 * @param WP_Post $latest_revision  The latest revision post object.
  3431 	 * @param WP_Post $post             The post object.
  3442 	 * @param WP_Post $post             The post object.
  3432 	 * @return bool Whether a revision should be made.
  3443 	 * @return bool Whether a revision should be made.
  3433 	 */
  3444 	 */
  3434 	public function _filter_revision_post_has_changed( $post_has_changed, $last_revision, $post ) {
  3445 	public function _filter_revision_post_has_changed( $post_has_changed, $latest_revision, $post ) {
  3435 		unset( $last_revision );
  3446 		unset( $latest_revision );
  3436 		if ( 'customize_changeset' === $post->post_type ) {
  3447 		if ( 'customize_changeset' === $post->post_type ) {
  3437 			$post_has_changed = $this->store_changeset_revision;
  3448 			$post_has_changed = $this->store_changeset_revision;
  3438 		}
  3449 		}
  3439 		return $post_has_changed;
  3450 		return $post_has_changed;
  3440 	}
  3451 	}
  3607 		 * restore them when a changeset is published, but they had been locked out from including
  3618 		 * restore them when a changeset is published, but they had been locked out from including
  3608 		 * their changes in the changeset.
  3619 		 * their changes in the changeset.
  3609 		 */
  3620 		 */
  3610 		$revisions = wp_get_post_revisions( $changeset_post_id, array( 'check_enabled' => false ) );
  3621 		$revisions = wp_get_post_revisions( $changeset_post_id, array( 'check_enabled' => false ) );
  3611 		foreach ( $revisions as $revision ) {
  3622 		foreach ( $revisions as $revision ) {
  3612 			if ( false !== strpos( $revision->post_name, "{$changeset_post_id}-autosave" ) ) {
  3623 			if ( str_contains( $revision->post_name, "{$changeset_post_id}-autosave" ) ) {
  3613 				$wpdb->update(
  3624 				$wpdb->update(
  3614 					$wpdb->posts,
  3625 					$wpdb->posts,
  3615 					array(
  3626 					array(
  3616 						'post_status' => 'auto-draft',
  3627 						'post_status' => 'auto-draft',
  3617 						'post_type'   => 'customize_changeset',
  3628 						'post_type'   => 'customize_changeset',
  4282 
  4293 
  4283 		<script type="text/html" id="tmpl-customize-notification">
  4294 		<script type="text/html" id="tmpl-customize-notification">
  4284 			<li class="notice notice-{{ data.type || 'info' }} {{ data.alt ? 'notice-alt' : '' }} {{ data.dismissible ? 'is-dismissible' : '' }} {{ data.containerClasses || '' }}" data-code="{{ data.code }}" data-type="{{ data.type }}">
  4295 			<li class="notice notice-{{ data.type || 'info' }} {{ data.alt ? 'notice-alt' : '' }} {{ data.dismissible ? 'is-dismissible' : '' }} {{ data.containerClasses || '' }}" data-code="{{ data.code }}" data-type="{{ data.type }}">
  4285 				<div class="notification-message">{{{ data.message || data.code }}}</div>
  4296 				<div class="notification-message">{{{ data.message || data.code }}}</div>
  4286 				<# if ( data.dismissible ) { #>
  4297 				<# if ( data.dismissible ) { #>
  4287 					<button type="button" class="notice-dismiss"><span class="screen-reader-text"><?php _e( 'Dismiss' ); ?></span></button>
  4298 					<button type="button" class="notice-dismiss"><span class="screen-reader-text">
       
  4299 						<?php
       
  4300 						/* translators: Hidden accessibility text. */
       
  4301 						_e( 'Dismiss' );
       
  4302 						?>
       
  4303 					</span></button>
  4288 				<# } #>
  4304 				<# } #>
  4289 			</li>
  4305 			</li>
  4290 		</script>
  4306 		</script>
  4291 
  4307 
  4292 		<script type="text/html" id="tmpl-customize-changeset-locked-notification">
  4308 		<script type="text/html" id="tmpl-customize-changeset-locked-notification">
  4349 				<?php esc_html_e( 'Share Preview Link' ); ?>
  4365 				<?php esc_html_e( 'Share Preview Link' ); ?>
  4350 			</p>
  4366 			</p>
  4351 			<p class="description customize-control-description"><?php esc_html_e( 'See how changes would look live on your website, and share the preview with people who can\'t access the Customizer.' ); ?></p>
  4367 			<p class="description customize-control-description"><?php esc_html_e( 'See how changes would look live on your website, and share the preview with people who can\'t access the Customizer.' ); ?></p>
  4352 			<div class="customize-control-notifications-container"></div>
  4368 			<div class="customize-control-notifications-container"></div>
  4353 			<div class="preview-link-wrapper">
  4369 			<div class="preview-link-wrapper">
  4354 				<label for="{{ elementPrefix }}customize-preview-link-input" class="screen-reader-text"><?php esc_html_e( 'Preview Link' ); ?></label>
  4370 				<label for="{{ elementPrefix }}customize-preview-link-input" class="screen-reader-text">
       
  4371 					<?php
       
  4372 					/* translators: Hidden accessibility text. */
       
  4373 					esc_html_e( 'Preview Link' );
       
  4374 					?>
       
  4375 				</label>
  4355 				<a href="" target="">
  4376 				<a href="" target="">
  4356 					<span class="preview-control-element" data-component="url"></span>
  4377 					<span class="preview-control-element" data-component="url"></span>
  4357 					<span class="screen-reader-text"><?php _e( '(opens in a new tab)' ); ?></span>
  4378 					<span class="screen-reader-text">
       
  4379 						<?php
       
  4380 						/* translators: Hidden accessibility text. */
       
  4381 						_e( '(opens in a new tab)' );
       
  4382 						?>
       
  4383 					</span>
  4358 				</a>
  4384 				</a>
  4359 				<input id="{{ elementPrefix }}customize-preview-link-input" readonly tabindex="-1" class="preview-control-element" data-component="input">
  4385 				<input id="{{ elementPrefix }}customize-preview-link-input" readonly tabindex="-1" class="preview-control-element" data-component="input">
  4360 				<button class="customize-copy-preview-link preview-control-element button button-secondary" data-component="button" data-copy-text="<?php esc_attr_e( 'Copy' ); ?>" data-copied-text="<?php esc_attr_e( 'Copied' ); ?>" ><?php esc_html_e( 'Copy' ); ?></button>
  4386 				<button class="customize-copy-preview-link preview-control-element button button-secondary" data-component="button" data-copy-text="<?php esc_attr_e( 'Copy' ); ?>" data-copied-text="<?php esc_attr_e( 'Copied' ); ?>" ><?php esc_html_e( 'Copy' ); ?></button>
  4361 			</div>
  4387 			</div>
  4362 		</script>
  4388 		</script>
  4572 	 * @since 4.4.0
  4598 	 * @since 4.4.0
  4573 	 *
  4599 	 *
  4574 	 * @param string $preview_url URL to be previewed.
  4600 	 * @param string $preview_url URL to be previewed.
  4575 	 */
  4601 	 */
  4576 	public function set_preview_url( $preview_url ) {
  4602 	public function set_preview_url( $preview_url ) {
  4577 		$preview_url       = esc_url_raw( $preview_url );
  4603 		$preview_url       = sanitize_url( $preview_url );
  4578 		$this->preview_url = wp_validate_redirect( $preview_url, home_url( '/' ) );
  4604 		$this->preview_url = wp_validate_redirect( $preview_url, home_url( '/' ) );
  4579 	}
  4605 	}
  4580 
  4606 
  4581 	/**
  4607 	/**
  4582 	 * Gets the initial URL to be previewed.
  4608 	 * Gets the initial URL to be previewed.
  4660 	 * @since 4.4.0
  4686 	 * @since 4.4.0
  4661 	 *
  4687 	 *
  4662 	 * @param string $return_url URL for return link.
  4688 	 * @param string $return_url URL for return link.
  4663 	 */
  4689 	 */
  4664 	public function set_return_url( $return_url ) {
  4690 	public function set_return_url( $return_url ) {
  4665 		$return_url       = esc_url_raw( $return_url );
  4691 		$return_url       = sanitize_url( $return_url );
  4666 		$return_url       = remove_query_arg( wp_removable_query_args(), $return_url );
  4692 		$return_url       = remove_query_arg( wp_removable_query_args(), $return_url );
  4667 		$return_url       = wp_validate_redirect( $return_url );
  4693 		$return_url       = wp_validate_redirect( $return_url );
  4668 		$this->return_url = $return_url;
  4694 		$this->return_url = $return_url;
  4669 	}
  4695 	}
  4670 
  4696 
  4683 		$referer                    = wp_get_referer();
  4709 		$referer                    = wp_get_referer();
  4684 		$excluded_referer_basenames = array( 'customize.php', 'wp-login.php' );
  4710 		$excluded_referer_basenames = array( 'customize.php', 'wp-login.php' );
  4685 
  4711 
  4686 		if ( $this->return_url ) {
  4712 		if ( $this->return_url ) {
  4687 			$return_url = $this->return_url;
  4713 			$return_url = $this->return_url;
       
  4714 
       
  4715 			$return_url_basename = wp_basename( parse_url( $this->return_url, PHP_URL_PATH ) );
       
  4716 			$return_url_query    = parse_url( $this->return_url, PHP_URL_QUERY );
       
  4717 
       
  4718 			if ( 'themes.php' === $return_url_basename && $return_url_query ) {
       
  4719 				parse_str( $return_url_query, $query_vars );
       
  4720 
       
  4721 				/*
       
  4722 				 * If the return URL is a page added by a theme to the Appearance menu via add_submenu_page(),
       
  4723 				 * verify that it belongs to the active theme, otherwise fall back to the Themes screen.
       
  4724 				 */
       
  4725 				if ( isset( $query_vars['page'] ) && ! isset( $_registered_pages[ "appearance_page_{$query_vars['page']}" ] ) ) {
       
  4726 					$return_url = admin_url( 'themes.php' );
       
  4727 				}
       
  4728 			}
  4688 		} elseif ( $referer && ! in_array( wp_basename( parse_url( $referer, PHP_URL_PATH ) ), $excluded_referer_basenames, true ) ) {
  4729 		} elseif ( $referer && ! in_array( wp_basename( parse_url( $referer, PHP_URL_PATH ) ), $excluded_referer_basenames, true ) ) {
  4689 			$return_url = $referer;
  4730 			$return_url = $referer;
  4690 		} elseif ( $this->preview_url ) {
  4731 		} elseif ( $this->preview_url ) {
  4691 			$return_url = $this->preview_url;
  4732 			$return_url = $this->preview_url;
  4692 		} else {
  4733 		} else {
  4693 			$return_url = home_url( '/' );
  4734 			$return_url = home_url( '/' );
  4694 		}
       
  4695 
       
  4696 		$return_url_basename = wp_basename( parse_url( $this->return_url, PHP_URL_PATH ) );
       
  4697 		$return_url_query    = parse_url( $this->return_url, PHP_URL_QUERY );
       
  4698 
       
  4699 		if ( 'themes.php' === $return_url_basename && $return_url_query ) {
       
  4700 			parse_str( $return_url_query, $query_vars );
       
  4701 
       
  4702 			/*
       
  4703 			 * If the return URL is a page added by a theme to the Appearance menu via add_submenu_page(),
       
  4704 			 * verify that it belongs to the active theme, otherwise fall back to the Themes screen.
       
  4705 			 */
       
  4706 			if ( isset( $query_vars['page'] ) && ! isset( $_registered_pages[ "appearance_page_{$query_vars['page']}" ] ) ) {
       
  4707 				$return_url = admin_url( 'themes.php' );
       
  4708 			}
       
  4709 		}
  4735 		}
  4710 
  4736 
  4711 		return $return_url;
  4737 		return $return_url;
  4712 	}
  4738 	}
  4713 
  4739 
  4892 				'stylesheet'  => $this->get_stylesheet(),
  4918 				'stylesheet'  => $this->get_stylesheet(),
  4893 				'active'      => $this->is_theme_active(),
  4919 				'active'      => $this->is_theme_active(),
  4894 				'_canInstall' => current_user_can( 'install_themes' ),
  4920 				'_canInstall' => current_user_can( 'install_themes' ),
  4895 			),
  4921 			),
  4896 			'url'                    => array(
  4922 			'url'                    => array(
  4897 				'preview'       => esc_url_raw( $this->get_preview_url() ),
  4923 				'preview'       => sanitize_url( $this->get_preview_url() ),
  4898 				'return'        => esc_url_raw( $this->get_return_url() ),
  4924 				'return'        => sanitize_url( $this->get_return_url() ),
  4899 				'parent'        => esc_url_raw( admin_url() ),
  4925 				'parent'        => sanitize_url( admin_url() ),
  4900 				'activated'     => esc_url_raw( home_url( '/' ) ),
  4926 				'activated'     => sanitize_url( home_url( '/' ) ),
  4901 				'ajax'          => esc_url_raw( admin_url( 'admin-ajax.php', 'relative' ) ),
  4927 				'ajax'          => sanitize_url( admin_url( 'admin-ajax.php', 'relative' ) ),
  4902 				'allowed'       => array_map( 'esc_url_raw', $this->get_allowed_urls() ),
  4928 				'allowed'       => array_map( 'sanitize_url', $this->get_allowed_urls() ),
  4903 				'isCrossDomain' => $this->is_cross_domain(),
  4929 				'isCrossDomain' => $this->is_cross_domain(),
  4904 				'home'          => esc_url_raw( home_url( '/' ) ),
  4930 				'home'          => sanitize_url( home_url( '/' ) ),
  4905 				'login'         => esc_url_raw( $login_url ),
  4931 				'login'         => sanitize_url( $login_url ),
  4906 			),
  4932 			),
  4907 			'browser'                => array(
  4933 			'browser'                => array(
  4908 				'mobile' => wp_is_mobile(),
  4934 				'mobile' => wp_is_mobile(),
  4909 				'ios'    => $this->is_ios(),
  4935 				'ios'    => $this->is_ios(),
  4910 			),
  4936 			),
  4951 					}
  4977 					}
  4952 				}
  4978 				}
  4953 			}
  4979 			}
  4954 		}
  4980 		}
  4955 
  4981 
       
  4982 		ob_start();
  4956 		?>
  4983 		?>
  4957 		<script type="text/javascript">
  4984 		<script>
  4958 			var _wpCustomizeSettings = <?php echo wp_json_encode( $settings ); ?>;
  4985 			var _wpCustomizeSettings = <?php echo wp_json_encode( $settings ); ?>;
  4959 			_wpCustomizeSettings.initialClientTimestamp = _.now();
  4986 			_wpCustomizeSettings.initialClientTimestamp = _.now();
  4960 			_wpCustomizeSettings.controls = {};
  4987 			_wpCustomizeSettings.controls = {};
  4961 			_wpCustomizeSettings.settings = {};
  4988 			_wpCustomizeSettings.settings = {};
  4962 			<?php
  4989 			<?php
  4987 			}
  5014 			}
  4988 			echo "})( _wpCustomizeSettings.controls );\n";
  5015 			echo "})( _wpCustomizeSettings.controls );\n";
  4989 			?>
  5016 			?>
  4990 		</script>
  5017 		</script>
  4991 		<?php
  5018 		<?php
       
  5019 		wp_print_inline_script_tag( wp_remove_surrounding_empty_script_tags( ob_get_clean() ) );
  4992 	}
  5020 	}
  4993 
  5021 
  4994 	/**
  5022 	/**
  4995 	 * Returns a list of devices to allow previewing.
  5023 	 * Returns a list of devices to allow previewing.
  4996 	 *
  5024 	 *
  5173 				$this,
  5201 				$this,
  5174 				'site_icon',
  5202 				'site_icon',
  5175 				array(
  5203 				array(
  5176 					'label'       => __( 'Site Icon' ),
  5204 					'label'       => __( 'Site Icon' ),
  5177 					'description' => sprintf(
  5205 					'description' => sprintf(
  5178 						'<p>' . __( 'Site Icons are what you see in browser tabs, bookmark bars, and within the WordPress mobile apps. Upload one here!' ) . '</p>' .
  5206 						/* translators: %s: Site Icon size in pixels. */
  5179 						/* translators: %s: Site icon size in pixels. */
  5207 						'<p>' . __( 'The Site Icon is what you see in browser tabs, bookmark bars, and within the WordPress mobile apps. It should be square and at least %s pixels.' ) . '</p>',
  5180 						'<p>' . __( 'Site Icons should be square and at least %s pixels.' ) . '</p>',
  5208 						'<code>512 &times; 512</code>'
  5181 						'<strong>512 &times; 512</strong>'
       
  5182 					),
  5209 					),
  5183 					'section'     => 'title_tagline',
  5210 					'section'     => 'title_tagline',
  5184 					'priority'    => 60,
  5211 					'priority'    => 60,
  5185 					'height'      => 512,
  5212 					'height'      => 512,
  5186 					'width'       => 512,
  5213 					'width'       => 512,
  5251 				'sanitize_callback'    => array( $this, '_sanitize_header_textcolor' ),
  5278 				'sanitize_callback'    => array( $this, '_sanitize_header_textcolor' ),
  5252 				'sanitize_js_callback' => 'maybe_hash_hex_color',
  5279 				'sanitize_js_callback' => 'maybe_hash_hex_color',
  5253 			)
  5280 			)
  5254 		);
  5281 		);
  5255 
  5282 
  5256 		// Input type: checkbox.
  5283 		// Input type: checkbox, with custom value.
  5257 		// With custom value.
       
  5258 		$this->add_control(
  5284 		$this->add_control(
  5259 			'display_header_text',
  5285 			'display_header_text',
  5260 			array(
  5286 			array(
  5261 				'settings' => 'header_textcolor',
  5287 				'settings' => 'header_textcolor',
  5262 				'label'    => __( 'Display Site Title and Tagline' ),
  5288 				'label'    => __( 'Display Site Title and Tagline' ),
  5275 					'section' => 'colors',
  5301 					'section' => 'colors',
  5276 				)
  5302 				)
  5277 			)
  5303 			)
  5278 		);
  5304 		);
  5279 
  5305 
  5280 		// Input type: color.
  5306 		// Input type: color, with sanitize_callback.
  5281 		// With sanitize_callback.
       
  5282 		$this->add_setting(
  5307 		$this->add_setting(
  5283 			'background_color',
  5308 			'background_color',
  5284 			array(
  5309 			array(
  5285 				'default'              => get_theme_support( 'custom-background', 'default-color' ),
  5310 				'default'              => get_theme_support( 'custom-background', 'default-color' ),
  5286 				'theme_supports'       => 'custom-background',
  5311 				'theme_supports'       => 'custom-background',
  5584 				'section' => 'background_image',
  5609 				'section' => 'background_image',
  5585 				'type'    => 'checkbox',
  5610 				'type'    => 'checkbox',
  5586 			)
  5611 			)
  5587 		);
  5612 		);
  5588 
  5613 
  5589 		// If the theme is using the default background callback, we can update
  5614 		/*
  5590 		// the background CSS using postMessage.
  5615 		 * If the theme is using the default background callback, we can update
       
  5616 		 * the background CSS using postMessage.
       
  5617 		 */
  5591 		if ( get_theme_support( 'custom-background', 'wp-head-callback' ) === '_custom_background_cb' ) {
  5618 		if ( get_theme_support( 'custom-background', 'wp-head-callback' ) === '_custom_background_cb' ) {
  5592 			foreach ( array( 'color', 'image', 'preset', 'position_x', 'position_y', 'size', 'repeat', 'attachment' ) as $prop ) {
  5619 			foreach ( array( 'color', 'image', 'preset', 'position_x', 'position_y', 'size', 'repeat', 'attachment' ) as $prop ) {
  5593 				$this->get_setting( 'background_' . $prop )->transport = 'postMessage';
  5620 				$this->get_setting( 'background_' . $prop )->transport = 'postMessage';
  5594 			}
  5621 			}
  5595 		}
  5622 		}
  5671 		/* Custom CSS */
  5698 		/* Custom CSS */
  5672 		$section_description  = '<p>';
  5699 		$section_description  = '<p>';
  5673 		$section_description .= __( 'Add your own CSS code here to customize the appearance and layout of your site.' );
  5700 		$section_description .= __( 'Add your own CSS code here to customize the appearance and layout of your site.' );
  5674 		$section_description .= sprintf(
  5701 		$section_description .= sprintf(
  5675 			' <a href="%1$s" class="external-link" target="_blank">%2$s<span class="screen-reader-text"> %3$s</span></a>',
  5702 			' <a href="%1$s" class="external-link" target="_blank">%2$s<span class="screen-reader-text"> %3$s</span></a>',
  5676 			esc_url( __( 'https://codex.wordpress.org/CSS' ) ),
  5703 			esc_url( __( 'https://developer.wordpress.org/advanced-administration/wordpress/css/' ) ),
  5677 			__( 'Learn more about CSS' ),
  5704 			__( 'Learn more about CSS' ),
  5678 			/* translators: Accessibility text. */
  5705 			/* translators: Hidden accessibility text. */
  5679 			__( '(opens in a new tab)' )
  5706 			__( '(opens in a new tab)' )
  5680 		);
  5707 		);
  5681 		$section_description .= '</p>';
  5708 		$section_description .= '</p>';
  5682 
  5709 
  5683 		$section_description .= '<p id="editor-keyboard-trap-help-1">' . __( 'When using a keyboard to navigate:' ) . '</p>';
  5710 		$section_description .= '<p id="editor-keyboard-trap-help-1">' . __( 'When using a keyboard to navigate:' ) . '</p>';
  5694 				__( 'The edit field automatically highlights code syntax. You can disable this in your <a href="%1$s" %2$s>user profile%3$s</a> to work in plain text mode.' ),
  5721 				__( 'The edit field automatically highlights code syntax. You can disable this in your <a href="%1$s" %2$s>user profile%3$s</a> to work in plain text mode.' ),
  5695 				esc_url( get_edit_profile_url() ),
  5722 				esc_url( get_edit_profile_url() ),
  5696 				'class="external-link" target="_blank"',
  5723 				'class="external-link" target="_blank"',
  5697 				sprintf(
  5724 				sprintf(
  5698 					'<span class="screen-reader-text"> %s</span>',
  5725 					'<span class="screen-reader-text"> %s</span>',
  5699 					/* translators: Accessibility text. */
  5726 					/* translators: Hidden accessibility text. */
  5700 					__( '(opens in a new tab)' )
  5727 					__( '(opens in a new tab)' )
  5701 				)
  5728 				)
  5702 			);
  5729 			);
  5703 			$section_description .= '</p>';
  5730 			$section_description .= '</p>';
  5704 		}
  5731 		}
  5761 				if ( 'page' === get_post_type( $post_id ) ) {
  5788 				if ( 'page' === get_post_type( $post_id ) ) {
  5762 					return true;
  5789 					return true;
  5763 				}
  5790 				}
  5764 			}
  5791 			}
  5765 		}
  5792 		}
  5766 		return 0 !== count( get_pages( array( 'number' => 1 ) ) );
  5793 
       
  5794 		return 0 !== count(
       
  5795 			get_pages(
       
  5796 				array(
       
  5797 					'number'       => 1,
       
  5798 					'hierarchical' => 0,
       
  5799 				)
       
  5800 			)
       
  5801 		);
  5767 	}
  5802 	}
  5768 
  5803 
  5769 	/**
  5804 	/**
  5770 	 * Adds settings from the POST data that were not added with code, e.g. dynamically-created settings for Widgets
  5805 	 * Adds settings from the POST data that were not added with code, e.g. dynamically-created settings for Widgets
  5771 	 *
  5806 	 *
  6004 		} elseif ( 'background_preset' === $setting->id ) {
  6039 		} elseif ( 'background_preset' === $setting->id ) {
  6005 			if ( ! in_array( $value, array( 'default', 'fill', 'fit', 'repeat', 'custom' ), true ) ) {
  6040 			if ( ! in_array( $value, array( 'default', 'fill', 'fit', 'repeat', 'custom' ), true ) ) {
  6006 				return new WP_Error( 'invalid_value', __( 'Invalid value for background size.' ) );
  6041 				return new WP_Error( 'invalid_value', __( 'Invalid value for background size.' ) );
  6007 			}
  6042 			}
  6008 		} elseif ( 'background_image' === $setting->id || 'background_image_thumb' === $setting->id ) {
  6043 		} elseif ( 'background_image' === $setting->id || 'background_image_thumb' === $setting->id ) {
  6009 			$value = empty( $value ) ? '' : esc_url_raw( $value );
  6044 			$value = empty( $value ) ? '' : sanitize_url( $value );
  6010 		} else {
  6045 		} else {
  6011 			return new WP_Error( 'unrecognized_setting', __( 'Unrecognized background setting.' ) );
  6046 			return new WP_Error( 'unrecognized_setting', __( 'Unrecognized background setting.' ) );
  6012 		}
  6047 		}
  6013 		return $value;
  6048 		return $value;
  6014 	}
  6049 	}
  6050 				$validity->add(
  6085 				$validity->add(
  6051 					'size_too_large',
  6086 					'size_too_large',
  6052 					__( 'This video file is too large to use as a header video. Try a shorter video or optimize the compression settings and re-upload a file that is less than 8MB. Or, upload your video to YouTube and link it with the option below.' )
  6087 					__( 'This video file is too large to use as a header video. Try a shorter video or optimize the compression settings and re-upload a file that is less than 8MB. Or, upload your video to YouTube and link it with the option below.' )
  6053 				);
  6088 				);
  6054 			}
  6089 			}
  6055 			if ( '.mp4' !== substr( $video, -4 ) && '.mov' !== substr( $video, -4 ) ) { // Check for .mp4 or .mov format, which (assuming h.264 encoding) are the only cross-browser-supported formats.
  6090 			if ( ! str_ends_with( $video, '.mp4' ) && ! str_ends_with( $video, '.mov' ) ) { // Check for .mp4 or .mov format, which (assuming h.264 encoding) are the only cross-browser-supported formats.
  6056 				$validity->add(
  6091 				$validity->add(
  6057 					'invalid_file_type',
  6092 					'invalid_file_type',
  6058 					sprintf(
  6093 					sprintf(
  6059 						/* translators: 1: .mp4, 2: .mov */
  6094 						/* translators: 1: .mp4, 2: .mov */
  6060 						__( 'Only %1$s or %2$s files may be used for header video. Please convert your video file and try again, or, upload your video to YouTube and link it with the option below.' ),
  6095 						__( 'Only %1$s or %2$s files may be used for header video. Please convert your video file and try again, or, upload your video to YouTube and link it with the option below.' ),
  6077 	 * @param WP_Error $validity
  6112 	 * @param WP_Error $validity
  6078 	 * @param mixed    $value
  6113 	 * @param mixed    $value
  6079 	 * @return mixed
  6114 	 * @return mixed
  6080 	 */
  6115 	 */
  6081 	public function _validate_external_header_video( $validity, $value ) {
  6116 	public function _validate_external_header_video( $validity, $value ) {
  6082 		$video = esc_url_raw( $value );
  6117 		$video = sanitize_url( $value );
  6083 		if ( $video ) {
  6118 		if ( $video ) {
  6084 			if ( ! preg_match( '#^https?://(?:www\.)?(?:youtube\.com/watch|youtu\.be/)#', $video ) ) {
  6119 			if ( ! preg_match( '#^https?://(?:www\.)?(?:youtube\.com/watch|youtu\.be/)#', $video ) ) {
  6085 				$validity->add( 'invalid_url', __( 'Please enter a valid YouTube URL.' ) );
  6120 				$validity->add( 'invalid_url', __( 'Please enter a valid YouTube URL.' ) );
  6086 			}
  6121 			}
  6087 		}
  6122 		}
  6095 	 *
  6130 	 *
  6096 	 * @param string $value URL.
  6131 	 * @param string $value URL.
  6097 	 * @return string Sanitized URL.
  6132 	 * @return string Sanitized URL.
  6098 	 */
  6133 	 */
  6099 	public function _sanitize_external_header_video( $value ) {
  6134 	public function _sanitize_external_header_video( $value ) {
  6100 		return esc_url_raw( trim( $value ) );
  6135 		return sanitize_url( trim( $value ) );
  6101 	}
  6136 	}
  6102 
  6137 
  6103 	/**
  6138 	/**
  6104 	 * Callback for rendering the custom logo, used in the custom_logo partial.
  6139 	 * Callback for rendering the custom logo, used in the custom_logo partial.
  6105 	 *
  6140 	 *