: str_replace(): Passing null to parameter #2 ($replace) of type array|string is deprecated in
echo "})( _wpCustomizeSettings.settings );\n";
// Serialize controls one by one to improve memory usage.
echo "(function ( c ){\n";
foreach ( $this->controls() as $control ) {
if ( $control->check_capabilities() ) {
wp_json_encode( $control->id ),
wp_json_encode( $control->json() )
echo "})( _wpCustomizeSettings.controls );\n";
wp_print_inline_script_tag( wp_remove_surrounding_empty_script_tags( ob_get_clean() ) );
* Returns a list of devices to allow previewing.
* @return array List of devices with labels and default setting.
public function get_previewable_devices() {
'label' => __( 'Enter desktop preview mode' ),
'label' => __( 'Enter tablet preview mode' ),
'label' => __( 'Enter mobile preview mode' ),
* Filters the available devices to allow previewing in the Customizer.
* @see WP_Customize_Manager::get_previewable_devices()
* @param array $devices List of devices with labels and default setting.
$devices = apply_filters( 'customize_previewable_devices', $devices );
* Registers some default controls.
public function register_controls() {
/* Themes (controls are loaded via ajax) */
new WP_Customize_Themes_Panel(
'title' => $this->theme()->display( 'Name' ),
'<p>' . __( 'Looking for a theme? You can search or browse the WordPress.org theme directory, install and preview themes, then activate them right here.' ) . '</p>' .
'<p>' . __( 'While previewing a new theme, you can continue to tailor things like widgets and menus, and explore theme-specific options.' ) . '</p>'
'capability' => 'switch_themes',
new WP_Customize_Themes_Section(
'title' => __( 'Installed themes' ),
'capability' => 'switch_themes',
if ( ! is_multisite() ) {
new WP_Customize_Themes_Section(
'title' => __( 'WordPress.org themes' ),
'filter_type' => 'remote',
'capability' => 'install_themes',
// Themes Setting (unused - the theme is considerably more fundamental to the Customizer experience).
new WP_Customize_Filter_Setting(
'capability' => 'switch_themes',
'title' => __( 'Site Identity' ),
'default' => get_option( 'blogname' ),
'capability' => 'manage_options',
'label' => __( 'Site Title' ),
'section' => 'title_tagline',
'default' => get_option( 'blogdescription' ),
'capability' => 'manage_options',
'label' => __( 'Tagline' ),
'section' => 'title_tagline',
// Add a setting to hide header text if the theme doesn't support custom headers.
if ( ! current_theme_supports( 'custom-header', 'header-text' ) ) {
'theme_supports' => array( 'custom-logo', 'header-text' ),
'sanitize_callback' => 'absint',
'label' => __( 'Display Site Title and Tagline' ),
'section' => 'title_tagline',
'settings' => 'header_text',
'capability' => 'manage_options',
'transport' => 'postMessage', // Previewed with JS in the Customizer controls window.
new WP_Customize_Site_Icon_Control(
'label' => __( 'Site Icon' ),
'description' => sprintf(
/* translators: %s: Site Icon size in pixels. */
'<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>',
'<code>512 × 512</code>'
'section' => 'title_tagline',
'theme_supports' => array( 'custom-logo' ),
'transport' => 'postMessage',
$custom_logo_args = get_theme_support( 'custom-logo' );
new WP_Customize_Cropped_Image_Control(
'section' => 'title_tagline',
'height' => isset( $custom_logo_args[0]['height'] ) ? $custom_logo_args[0]['height'] : null,
'width' => isset( $custom_logo_args[0]['width'] ) ? $custom_logo_args[0]['width'] : null,
'flex_height' => isset( $custom_logo_args[0]['flex-height'] ) ? $custom_logo_args[0]['flex-height'] : null,
'flex_width' => isset( $custom_logo_args[0]['flex-width'] ) ? $custom_logo_args[0]['flex-width'] : null,
'button_labels' => array(
'select' => __( 'Select logo' ),
'change' => __( 'Change logo' ),
'remove' => __( 'Remove' ),
'default' => __( 'Default' ),
'placeholder' => __( 'No logo selected' ),
'frame_title' => __( 'Select logo' ),
'frame_button' => __( 'Choose logo' ),
$this->selective_refresh->add_partial(
'settings' => array( 'custom_logo' ),
'selector' => '.custom-logo-link',
'render_callback' => array( $this, '_render_custom_logo_partial' ),
'container_inclusive' => true,
'title' => __( 'Colors' ),
'theme_supports' => array( 'custom-header', 'header-text' ),
'default' => get_theme_support( 'custom-header', 'default-text-color' ),
'sanitize_callback' => array( $this, '_sanitize_header_textcolor' ),
'sanitize_js_callback' => 'maybe_hash_hex_color',
// Input type: checkbox, with custom value.
'settings' => 'header_textcolor',
'label' => __( 'Display Site Title and Tagline' ),
'section' => 'title_tagline',
new WP_Customize_Color_Control(
'label' => __( 'Header Text Color' ),
// Input type: color, with sanitize_callback.
'default' => get_theme_support( 'custom-background', 'default-color' ),
'theme_supports' => 'custom-background',
'sanitize_callback' => 'sanitize_hex_color_no_hash',
'sanitize_js_callback' => 'maybe_hash_hex_color',
new WP_Customize_Color_Control(
'label' => __( 'Background Color' ),
if ( current_theme_supports( 'custom-header', 'video' ) ) {
$title = __( 'Header Media' );
$description = '<p>' . __( 'If you add a video, the image will be used as a fallback while the video loads.' ) . '</p>';
$width = absint( get_theme_support( 'custom-header', 'width' ) );
$height = absint( get_theme_support( 'custom-header', 'height' ) );
if ( $width && $height ) {
$control_description = sprintf(
/* translators: 1: .mp4, 2: Header size in pixels. */
__( 'Upload your video in %1$s format and minimize its file size for best results. Your theme recommends dimensions of %2$s pixels.' ),
sprintf( '<strong>%s × %s</strong>', $width, $height )
$control_description = sprintf(
/* translators: 1: .mp4, 2: Header width in pixels. */
__( 'Upload your video in %1$s format and minimize its file size for best results. Your theme recommends a width of %2$s pixels.' ),
sprintf( '<strong>%s</strong>', $width )
$control_description = sprintf(
/* translators: 1: .mp4, 2: Header height in pixels. */
__( 'Upload your video in %1$s format and minimize its file size for best results. Your theme recommends a height of %2$s pixels.' ),
sprintf( '<strong>%s</strong>', $height )
$title = __( 'Header Image' );
$control_description = '';
'description' => $description,
'theme_supports' => 'custom-header',
'theme_supports' => array( 'custom-header', 'video' ),
'transport' => 'postMessage',
'sanitize_callback' => 'absint',
'validate_callback' => array( $this, '_validate_header_video' ),
'theme_supports' => array( 'custom-header', 'video' ),
'transport' => 'postMessage',
'sanitize_callback' => array( $this, '_sanitize_external_header_video' ),
'validate_callback' => array( $this, '_validate_external_header_video' ),
new WP_Customize_Filter_Setting(
'default' => sprintf( get_theme_support( 'custom-header', 'default-image' ), get_template_directory_uri(), get_stylesheet_directory_uri() ),
'theme_supports' => 'custom-header',
new WP_Customize_Header_Image_Setting(
'theme_supports' => 'custom-header',
* Switch image settings to postMessage when video support is enabled since
* it entails that the_custom_header_markup() will be used, and thus selective
* refresh can be utilized.
if ( current_theme_supports( 'custom-header', 'video' ) ) {
$this->get_setting( 'header_image' )->transport = 'postMessage';
$this->get_setting( 'header_image_data' )->transport = 'postMessage';
new WP_Customize_Media_Control(
'theme_supports' => array( 'custom-header', 'video' ),
'label' => __( 'Header Video' ),
'description' => $control_description,
'section' => 'header_image',
'active_callback' => 'is_header_video_active',
'theme_supports' => array( 'custom-header', 'video' ),
'description' => __( 'Or, enter a YouTube URL:' ),
'section' => 'header_image',
'active_callback' => 'is_header_video_active',
$this->add_control( new WP_Customize_Header_Image_Control( $this ) );
$this->selective_refresh->add_partial(
'selector' => '#wp-custom-header',
'render_callback' => 'the_custom_header_markup',
'settings' => array( 'header_video', 'external_header_video', 'header_image' ), // The image is used as a video fallback here.
'container_inclusive' => true,
'title' => __( 'Background Image' ),
'theme_supports' => 'custom-background',
'default' => get_theme_support( 'custom-background', 'default-image' ),
'theme_supports' => 'custom-background',
'sanitize_callback' => array( $this, '_sanitize_background_setting' ),
new WP_Customize_Background_Image_Setting(
'background_image_thumb',
'theme_supports' => 'custom-background',
'sanitize_callback' => array( $this, '_sanitize_background_setting' ),
$this->add_control( new WP_Customize_Background_Image_Control( $this ) );
'default' => get_theme_support( 'custom-background', 'default-preset' ),