customizer cover

We use WordPress build-in customizer to allow our buyers to change the look & feel of our products. There are tons of reasons using it over the frameworks and theme option panels. It comes really handy when you want to play around with visual appearance of the theme without making the changes live. Also, it doesn’t add any overhead as 3rd party frameworks do. Lastly, it’s so much beyond anything else I’ve tried so far from UX point of view.

However, till WordPress 4.0 customizer had very limited set of controls which were available to developers to use out of the box. Essentially only text input fields, select, radio and checkboxes were available. In WP 4.0 code was rewritten and now all the HTML5 input types are supported as well as <textarea>.

But even that didn’t allow enough freedom when we were building MentalPress theme. We wanted the user to intuitively change the layout of the footer, which is dynamically build with widgets.

New Customize Control

There are 3 different parts which make up entire customizer:

  • Settings are values stored in the database.
  • Sections & panels are containers for separate controls and you see them on the left hand side of the screen when you open up customizer screen. Sections open like accordion UI components. Panels are containers for multiple sections, so one can group relevant sections together.
  • Controls are the UI elements where user interacts with settings. The simplest example is the text <input> field.

There is the fourth part which binds all the pieces together and is not relevant to this article: a customizer manager.

What I essentially wanted to achieve is to create a new control which allows admin WordPress user to intuitively change:

  • number of columns in the footer and
  • how wide each column is (according to the 12-col grid we use in our themes).

Picture is worth a thousand words, so here is the screenshot of the newly created customizer control:

screenshot of customizer
Screenshot from customizer of the new footer layout control.

Here is a gif what we eventually came up with and demonstrates user interacting with the new control whereas the layout on the right adapts accordingly:

animated gif showcasing interating
User interacting with the footer layout control in customizer

Technical Breakdown

I faced quite some challenges when coding this little new feature, so I decided to share it with you in a blogpost and save you some deep diving in WordPress core code.

Backend and customizer

I will not explain into the details, let the nicely formatted documented code speak for itself. I decided to create a gist out of that file, you can find it on this link.

How to use it?

It’s easy, in the class where you register all the other controls (learn about this here) simply a add new control to customizer manager as:

$this->wp_customize->add_control( new WP_Customize_Range_Control(
    $this->wp_customize,
    'footer_widgets_layout',
    array(
        'priority'    => 1,
        'label'       => _x( 'Footer widgets layout', 'backend', 'mentalpress_wp' ),
        'description' => _x( 'Select number of widget you want in the footer and then with the slider rearrange the layout', 'backend', 'mentalpress_wp' ),
        'section'     => 'section_footer',
        'input_attrs' => array(
            'min'     => 0,
            'max'     => 12,
            'step'    => 1,
            'maxCols' => 6,
        )
    )
) );

Frontend

Outputting the right markup on the frontend was trickier than I thought. I wanted a clean HTML output, with bootstrap’s col-*-* classes, avoiding JS hacks if possible. The problem is that when you register the dynamic sidebar in the theme, you should pass hardcoded HTML wrapper for all the widgets, usually something like that:

// Header
register_sidebar(
    array(
        'name'          => _x( 'Header', 'backend', 'mentalpress_wp' ),
        'id'            => 'header-widgets',
        'description'   => _x( 'Header area for Icon Box and Social Icons widgets.', 'backend', 'mentalpress_wp' ),
        'before_widget' => '<div class="col-xs-12  col-md-4"><div class="widget  %2$s">',
        'after_widget'  => '</div></div>'
    )
);

The thing is that every widget in the footer should have different wrapper with different col-* class. Luckily, WordPress filters come to the rescue, namely dynamic_sidebar_params (link to core trac).

By utilizing this filter and some PHP magic with static variables inside functions I did the trick:

/**
 * Filter the dynamic sidebars and alter the BS col classes for the footer wigets
 * @param  array $params
 * @return array
 */
if ( ! function_exists( 'pt_footer_widgets_params' ) ) {
    function pt_footer_widgets_params( $params ) {
        static $counter = 0;
        static $first_row = true;
        $footer_widgets_layout_array = pt_footer_widgets_layout_array();

        if ( $params[0]['id'] === 'footer-widgets' ) {
            // 'before_widget' contains %d, see inc/theme-sidebars.php
            $params[0]['before_widget'] = sprintf( $params[0]['before_widget'], $footer_widgets_layout_array[$counter] );

            // first widget in the any non-first row
            if ( false === $first_row && 0 === $counter ) {
                $params[0]['before_widget'] = '</div><div class="row">' . $params[0]['before_widget'];
            }

            $counter++;
        }

        end( $footer_widgets_layout_array );
        if ( $counter > key( $footer_widgets_layout_array ) ) {
            $counter = 0;
            $first_row = false;
        }

        return $params;
    }
    add_filter( 'dynamic_sidebar_params', 'pt_footer_widgets_params', 9, 1 );
}

Notice the sprintf( $params[0]['before_widget'], $footer_widgets_layout_array[$counter] ); ? Well, another light hack was needed. When registering widget I had to escape the %d placeholder with double %%, because the before_widget string already goes through the sprintf function here. Long story short, here’s how the register_sidebar looks like after all:

// Footer
$footer_widgets_num = count( pt_footer_widgets_layout_array() );

// only register if not 0
if ( $footer_widgets_num > 0 ) {
    register_sidebar(
        array(
            'name'          => _x( 'Footer', 'backend', 'mentalpress_wp' ),
            'id'            => 'footer-widgets',
            'description'   => sprintf( _x( 'Footer area works best with %d widgets. This number can be changed in the Appearance → Customize → Theme Options → Footer.', 'backend', 'mentalpress_wp' ), $footer_widgets_num ),
            'before_widget' => '<div class="col-xs-12  col-md-%%d"><div class="widget  %2$s">', // %%d is replaced dynamically in filter 'dynamic_sidebar_params'
            'after_widget'  => '</div></div>',
            'before_title'  => '<h6 class="footer-top__headings">',
            'after_title'   => '</h6>'

    );
}

Good UI matters

Tiny details like this dramatically help your users to achieve desired result and consequently decrease the support requests. We’ve experienced this several times already. When we notice the same question is repeating over and over again on our support, that is a sign something is not obvious to the user. The best you can do as an author of the products is to improve the user interface and solve the problem once and for all in the best possible way.

Win for the user, win for you!

I would be glad to hear any improvement that come to your mind after reading this blogpost, share it with me in the comments & happy WordPressing!

Take a Look at Our WordPress Themes

Choose from a wide range of beautiful niche designs that you can try for free.

View All WordPress Themes
About the Author
Since I built my first website in primary school I've had a strong passion for web development. When not visiting conferences, giving talks or organizing local development related events, I focus on fast and highly optimized online solutions. I'm a windsurfer, snowboarder and beer lover in my leisure time.