*/
final class WP_Customize_Manager {
/**
- * An instance of the theme that is being customized.
+ * An instance of the theme being previewed.
*
* @var WP_Theme
*/
protected $original_stylesheet;
/**
- * Whether filters have been set to change the active theme to the theme being
- * customized.
+ * Whether this is a Customizer pageload.
*
* @var boolean
*/
*/
public $widgets;
- protected $settings = array();
- protected $sections = array();
- protected $controls = array();
+ protected $settings = array();
+ protected $containers = array();
+ protected $panels = array();
+ protected $sections = array();
+ protected $controls = array();
protected $nonce_tick;
*/
public function __construct() {
require( ABSPATH . WPINC . '/class-wp-customize-setting.php' );
+ require( ABSPATH . WPINC . '/class-wp-customize-panel.php' );
require( ABSPATH . WPINC . '/class-wp-customize-section.php' );
require( ABSPATH . WPINC . '/class-wp-customize-control.php' );
require( ABSPATH . WPINC . '/class-wp-customize-widgets.php' );
show_admin_bar( false );
- if ( ! current_user_can( 'edit_theme_options' ) )
+ if ( ! current_user_can( 'customize' ) ) {
$this->wp_die( -1 );
+ }
$this->original_stylesheet = get_stylesheet();
$this->wp_die( -1 );
}
- // All good, let's do some internal business to preview the theme.
$this->start_previewing_theme();
}
*
* @since 3.4.0
*/
- function after_setup_theme() {
+ public function after_setup_theme() {
if ( ! $this->doing_ajax() && ! validate_current_theme() ) {
wp_redirect( 'themes.php?broken=true' );
exit;
}
/**
- * Start previewing the selected theme by adding filters to change the current theme.
+ * If the theme to be previewed isn't the active theme, add filter callbacks
+ * to swap it out at runtime.
*
* @since 3.4.0
*/
return $this->controls;
}
+ /**
+ * Get the registered containers.
+ *
+ * @since 4.0.0
+ *
+ * @return array
+ */
+ public function containers() {
+ return $this->containers;
+ }
+
/**
* Get the registered sections.
*
return $this->sections;
}
+ /**
+ * Get the registered panels.
+ *
+ * @since 4.0.0
+ * @access public
+ *
+ * @return array Panels.
+ */
+ public function panels() {
+ return $this->panels;
+ }
+
/**
* Checks if the current theme is active.
*
$this->prepare_controls();
wp_enqueue_script( 'customize-preview' );
+ add_action( 'wp', array( $this, 'customize_preview_override_404_status' ) );
add_action( 'wp_head', array( $this, 'customize_preview_base' ) );
add_action( 'wp_head', array( $this, 'customize_preview_html5' ) );
add_action( 'wp_footer', array( $this, 'customize_preview_settings' ), 20 );
do_action( 'customize_preview_init', $this );
}
+ /**
+ * Prevent sending a 404 status when returning the response for the customize
+ * preview, since it causes the jQuery AJAX to fail. Send 200 instead.
+ *
+ * @since 4.0.0
+ * @access public
+ */
+ public function customize_preview_override_404_status() {
+ if ( is_404() ) {
+ status_header( 200 );
+ }
+ }
+
/**
* Print base element for preview frame.
*
public function customize_preview_settings() {
$settings = array(
'values' => array(),
- 'channel' => esc_js( $_POST['customize_messenger_channel'] ),
+ 'channel' => wp_unslash( $_POST['customize_messenger_channel'] ),
+ 'activeControls' => array(),
);
if ( 2 == $this->nonce_tick ) {
foreach ( $this->settings as $id => $setting ) {
$settings['values'][ $id ] = $setting->js_value();
}
+ foreach ( $this->controls as $id => $control ) {
+ $settings['activeControls'][ $id ] = $control->active();
+ }
?>
<script type="text/javascript">
unset( $this->settings[ $id ] );
}
+ /**
+ * Add a customize panel.
+ *
+ * @since 4.0.0
+ * @access public
+ *
+ * @param WP_Customize_Panel|string $id Customize Panel object, or Panel ID.
+ * @param array $args Optional. Panel arguments. Default empty array.
+ */
+ public function add_panel( $id, $args = array() ) {
+ if ( is_a( $id, 'WP_Customize_Panel' ) ) {
+ $panel = $id;
+ }
+ else {
+ $panel = new WP_Customize_Panel( $this, $id, $args );
+ }
+
+ $this->panels[ $panel->id ] = $panel;
+ }
+
+ /**
+ * Retrieve a customize panel.
+ *
+ * @since 4.0.0
+ * @access public
+ *
+ * @param string $id Panel ID to get.
+ * @return WP_Customize_Panel Requested panel instance.
+ */
+ public function get_panel( $id ) {
+ if ( isset( $this->panels[ $id ] ) ) {
+ return $this->panels[ $id ];
+ }
+ }
+
+ /**
+ * Remove a customize panel.
+ *
+ * @since 4.0.0
+ * @access public
+ *
+ * @param string $id Panel ID to remove.
+ */
+ public function remove_panel( $id ) {
+ unset( $this->panels[ $id ] );
+ }
+
/**
* Add a customize section.
*
}
/**
- * Prepare settings and sections.
+ * Prepare panels, sections, and controls.
*
* For each, check if required related components exist,
* whether the user has the necessary capabilities,
$controls = array();
foreach ( $this->controls as $id => $control ) {
- if ( ! isset( $this->sections[ $control->section ] ) || ! $control->check_capabilities() )
+ if ( ! isset( $this->sections[ $control->section ] ) || ! $control->check_capabilities() ) {
continue;
+ }
$this->sections[ $control->section ]->controls[] = $control;
$controls[ $id ] = $control;
$sections = array();
foreach ( $this->sections as $section ) {
- if ( ! $section->check_capabilities() || ! $section->controls )
+ if ( ! $section->check_capabilities() || ! $section->controls ) {
continue;
+ }
usort( $section->controls, array( $this, '_cmp_priority' ) );
- $sections[] = $section;
+
+ if ( ! $section->panel ) {
+ // Top-level section.
+ $sections[] = $section;
+ } else {
+ // This section belongs to a panel.
+ if ( isset( $this->panels [ $section->panel ] ) ) {
+ $this->panels[ $section->panel ]->sections[] = $section;
+ }
+ }
}
$this->sections = $sections;
+
+ // Prepare panels.
+ // Reversing makes uasort sort by time added when conflicts occur.
+ $this->panels = array_reverse( $this->panels );
+ uasort( $this->panels, array( $this, '_cmp_priority' ) );
+ $panels = array();
+
+ foreach ( $this->panels as $panel ) {
+ if ( ! $panel->check_capabilities() || ! $panel->sections ) {
+ continue;
+ }
+
+ usort( $panel->sections, array( $this, '_cmp_priority' ) );
+ $panels[] = $panel;
+ }
+ $this->panels = $panels;
+
+ // Sort panels and top-level sections together.
+ $this->containers = array_merge( $this->panels, $this->sections );
+ uasort( $this->containers, array( $this, '_cmp_priority' ) );
}
/**
$this->add_control( new WP_Customize_Background_Image_Control( $this ) );
$this->add_setting( 'background_repeat', array(
- 'default' => 'repeat',
+ 'default' => get_theme_support( 'custom-background', 'default-repeat' ),
'theme_supports' => 'custom-background',
) );
) );
$this->add_setting( 'background_position_x', array(
- 'default' => 'left',
+ 'default' => get_theme_support( 'custom-background', 'default-position-x' ),
'theme_supports' => 'custom-background',
) );
) );
$this->add_setting( 'background_attachment', array(
- 'default' => 'fixed',
+ 'default' => get_theme_support( 'custom-background', 'default-attachment' ),
'theme_supports' => 'custom-background',
) );
'section' => 'background_image',
'type' => 'radio',
'choices' => array(
- 'fixed' => __('Fixed'),
'scroll' => __('Scroll'),
+ 'fixed' => __('Fixed'),
),
) );
$locations = get_registered_nav_menus();
$menus = wp_get_nav_menus();
- $menu_locations = get_nav_menu_locations();
$num_locations = count( array_keys( $locations ) );
$this->add_section( 'nav', array(
return $color;
}
-};
+}
/**
* Sanitizes a hex color.