Archive for May 2015

Been a while since I wrote something. Let’s talk about some of the new stuff available in the Customizer.

Forget about some of part two

First, back in part two, I had a bit about Surfacing the Customizer. That bit is outdated now, WordPress does this for you in later versions. So, yeah, skip that.

Shiny new thing: Panels

Okay, so Panels aren’t that new. They were added in WordPress 4.0. Basically, they’re sliding containers for sections. Having trouble fitting all your settings on the screen? Group the various sections up into Panels. Panels show up as an item in the main list, and when you click the arrow next to them, the whole list glides off screen to show only those sections.

So, now we have four things: Panels, Sections, Controls, and Settings.

  • Panels group Sections together
  • Sections contain Controls
  • Controls are what the user changes
  • Settings define what the Controls change

Creating a panel is easy:

$wp_customize->add_panel( 'some_panel', array(
   'title' => 'Panel 1',
   'description' => 'This is a description of this panel',
   'priority' => 10,
) );

Adding a section to that panel is just as easy:

$wp_customize->add_section( 'themedemo_panel_settings', array(
 'title' => 'More Stuff',
 'priority' => 10,
 'panel' => 'some_panel',
) );

All that’s new is a panel setting to tell the section to go into that panel. Simple.

Active Callbacks

One of the problems with the Customizer was that it displayed settings and showed them changing on the site to your right, but the site being displayed is the actual site. Meaning that you can navigate on it. Sometimes, the controls being shown don’t necessarily apply to the actual site that you’re seeing.

Example: If you have a control to change the color of something in the sidebar, but then are looking at a page which has no sidebar, then you have no visual feedback to tell you what the change looks like.

To fix this, “active callbacks” are used.

The active_callback is simply a new parameter that you can pass into Panels, Sections, or Controls. It can contain the name of a function, and that function will be called when the page changes. The function should return true or false (or equivalent) to indicate whether or not the element of the customizer should be shown for that page.

So, if you have a whole Panel that only make sense when the user is looking at Front Page of the site (and not an individual post), then you can do this:

$wp_customize->add_panel( 'front_page_panel', array(
   'title' => 'Front Page Stuff',
   'description' => 'Stuff that you can change about the Front Page',
   'priority' => 10,
   'active_callback' => 'is_front_page',
) );

And voila, when the user is not looking at the front page, the panel simply disappears.

You can use any of the normal WordPress Template Tags for this, or write your own function if you want to be more specific about it.

Edit: As pointed out in the comments, this will not work with ALL of the Template Tags. In particular, is_single won’t work because of the optional parameter it can take. You can define a wrapper for these methods instead, to get the same effect. Example:

function callback_single() { return is_single(); }
...
   'active_callback'=>'callback_single'
...

Fun with Active Callbacks

If you do need to write your own callback function, note that the function receives the object in question when it’s called. So, if you attach an active_callback to a Panel, your function will get a argument of the WP_Customize_Panel object in question passed to it. Sections get WP_Customize_Section and such. You can use the information in these to decide whether the panel (or whatever) should be shown for that page.

So, how do we use that object? Well, you can use this to make whether certain controls show or not dependent on the values of other settings. All the various items you can use this on have a link back to the main WP_Customize_Manager. That class has a get_setting function, which you can use to determine what to do.

So, let’s make a control that causes other controls to appear, dependent on a setting.

First, let’s make a simple radio selection control:

$wp_customize->add_setting( 'demo_radio_control', array(
   'default'        => 'a',
) );

$wp_customize->add_control( 'demo_radio_control', array(
   'label'      => 'radio_control',
   'section'    => 'themedemo_panel_settings',
   'settings'   => 'demo_radio_control',
   'type'       => 'radio',
   'choices'    => array(
   'a' => 'Choice A',
   'b' => 'Choice B',
   ),
) );

Now, we need to make two other controls, one for each choice. You can actually make as many as you like, we’ll keep it simple.

First, the control for choice A. Let’s make it a simple text control.

$wp_customize->add_setting( 'choice_a_text', array(
   'default' => '',
) );

$wp_customize->add_control( 'choice_a_text', array(
   'label'      => 'Choice A: ',
   'section'    => 'themedemo_panel_settings',
   'type'       => 'text',
   'active_callback' => 'choice_a_callback',
) );

We’ll need that callback function to detect if choice A is selected in the radio control, and return true if it is, and false otherwise. Like so:

function choice_a_callback( $control ) {
   if ( $control->manager->get_setting('demo_radio_control')->value() == 'a' ) {
      return true;
   } else {
      return false;
   }
}

You can simplify that if you like, I spelled it out with an if statement so as to be clear as to what is happening.

panel1

Now for choice B, let’s make it display a color control instead:

$wp_customize->add_setting( 'choice_b_color', array(
   'default' => '#123456',
) );

$wp_customize->add_control( new WP_Customize_Color_Control( $wp_customize, 'choice_b_color', array(
   'label'   => 'Choice B',
   'section' => 'themedemo_panel_settings',
   'settings'   => 'choice_b_color',
   'active_callback' => 'choice_b_callback',
) ) );

And its callback:

function choice_b_callback( $control ) {
   if ( $control->manager->get_setting('demo_radio_control')->value() == 'b' ) {
      return true;
   } else {
      return false;
   }
}
panel1-b

Now, note that the callbacks are very similar. Seems like repeated code, doesn’t it? Well, it is, but remember that the $control here is the whole WP_Customize_Control object. We can use the same callback and simply check which control is calling it here instead.

function choice_callback( $control ) {
   $radio_setting = $control->manager->get_setting('demo_radio_control')->value();
   $control_id = $control->id;

   if ( $control_id == 'choice_a_text'  && $radio_setting == 'a' ) return true;
   if ( $control_id == 'choice_b_color' && $radio_setting == 'b' ) return true;

   return false;
}

So, instead of using two different callbacks, we just point our controls to this callback, which figures out what should show up for which setting. I’m sure you can simplify this further, depending on your particular needs.

One more thing: Customizing the Customizer

Not everybody likes the style of the Customizer. Maybe it clashes with your theme. Maybe you just want to tweak it a bit. Maybe you dislike that gray background color, and a more soothing blue would go better for your theme.

add_action( 'customize_controls_enqueue_scripts', 'themedemo_customizer_style');
function themedemo_customizer_style() {
   wp_add_inline_style( 'customize-controls', '.wp-full-overlay-sidebar { background: #abcdef }');
}

Or maybe you don’t think the Customizer area is wide enough… be careful with this one though, consider mobile users as well.

add_action( 'customize_controls_enqueue_scripts', 'themedemo_customizer_style');
function themedemo_customizer_style() {
   wp_add_inline_style( 'customize-controls', '.wp-full-overlay-sidebar { width: 400px } .wp-full-overlay.expanded { margin-left: 400px } ');
}

You can enqueue whole extra CSS files instead, if you like. Or, if you have special needs for javascript in some of your controls, and there’s libraries necessary to implement them, then you can enqueue those libraries here as well.

Shortlink: