Using Javascript to improve the User Experience of the Customize Panel

The problem is, Once we un-check the “Show Read More Link” option, Sometimes the “Read More Text” Control is hiding right away and Sometimes it is only getting hidden after refreshing the Customize Panel.

Wouldn’t be great if “Read More Text” Control is shown/hidden right away as soon as we click on “Show Read More Link” Control?

It is definitely doable! 

We can achieve this with the help of some Javascript. And it is not at all scary. Some developers think of it that way. But actually, it is not. 

Anyway, like it or not, Javascript is the only way to enhance User Experience when it comes to web pages! So let’s fix our problem using Javascript.

Customize Panel provides us with a neat little Javascript Customization API and it is extremely easy to use it.

The first thing we need to do is, we need to change the “transport” argument of the “nd_dosth_show_readmore” Setting to “postMessage”. 

$wp_customize->add_setting( 'nd_dosth_show_readmore',
    array(
        'type'              => 'option',
        'default'           => true,
        'sanitize_callback' => 'nd_dosth_sanitize_checkbox',
        'transport'         => 'postMessage',
    )
);

Note: Remember, the “transport” argument is only set on a particular Setting. Not its Control. 

Go ahead and Do it! You must follow along with me to understand upcoming problems and their solutions.

As I have said before, If you provide “refresh” for the “transport” argument, WordPress refresh the entire Customize Panel to show you the changes affected by the Setting. It is just like a normal web page refresh and slows you down. 

This is the default behavior of the Customize Panel. But, If you provide “postMessage”, WordPress will only refresh a part of Customize Panel where the change took place. It is like AJAX and improves user experience. 

Now that we have changed the “transport” method to “postMessage” if you now test out the “Show Read More Link” Control,  you’ll notice that it is no longer working as expected. 

The Customize Panel is not getting refreshed like it used to be. 

Turning off the “Show Read More Link” will no longer hide the “Read More Text” Control and “Continue Reading” Link inside the Site Preview. This is not malfunctioning. This is the correct behavior of a Setting with “postMessage” transport method.

The ultimate goal is to hide both of them using the Javascript and we can’t hide them in a single go and two different action hooks are involved here.

First, let’s hide the “Read More Text” Control using the customize_controls_enqueue_scripts action hook. This action hook is just like wp_enqueue_scripts action hook. 

The customize_controls_enqueue_scripts action hook allows us to enqueue scripts to the Customize Panel and allows us to deal with the Settings and Controls of the Customize Panel. Not anything else.

Remember, It doesn’t care about the Site Preview side of the Customize Panel. If you try to hide an element from the Site Preview, it is not going to work. There is another hook for that purpose and we will see that shortly.

For now, let’s focus on hiding the “Read More Text” Control and we should hide it only when “Show Read More Link” Control is turned off. That’s our goal. 

So, go back to the customize.php file and put the following code at the end of the file:


/**
 * Register customize panel controls scripts.
 */
function nd_dosth_customize_controls_register_scripts() {
    wp_enqueue_script(
        'nd-dosth-customize-active-callbacks',
        get_stylesheet_directory_uri() . '/assets/js/customize-active-callback.js',
        array(),
        '',
        true
    );
}
add_action( 'customize_controls_enqueue_scripts', 'nd_dosth_customize_controls_register_scripts', 0 );

In the above code, we are just enqueuing a Javascript file to the Customize Panel and the code inside this Javascript file will be executed only when we are interacting with the Customize Panel.

We did not create this file yet! 

So, go ahead and create a new file called customize-active-callback.js inside the assets/js directory. Here is the full path to the file:

/wp-content/themes/nd-dosth/assets/js/customize-active-callback.js

Next, open up the customize-active-callback.js file and put the following Code inside it:


(function($){
    // Show "Read More Text" Control only if "Show Read More Link" is set to true
    wp.customize.control( 'nd_dosth_readmore_text', function( readmore_text_control ) {
        var show_readmore_setting = wp.customize( 'nd_dosth_show_readmore' );
        readmore_text_control.active.set( true == show_readmore_setting.get() );
        
        show_readmore_setting.bind( function( updated_value_of_show_readmore_setting ) {
            readmore_text_control.active.set( true == updated_value_of_show_readmore_setting );
        } );
    } );
})(jQuery); 

Let’s break it down piece by piece.

wp.customize.control( 'nd_dosth_readmore_text', function( readmore_text_control ) {
// Logic for hiding/showing a control goes here
} );

First, we are getting the “Read More Text” Control with the help of wp.customize.control method.

The wp.customize.control method accepts a callback as the second parameter. This callback function will be executed as soon as we enter the Customize Panel. 

We have to access the “Read More Text” Control inside this callback to show it or hide it. So we are passing the “Read More Text” Control as a parameter to this callback function.


wp.customize( 'nd_dosth_show_readmore' );

 Next, we are getting the “Show Read More Link” Setting with the help of wp.customize method. I’d suggest you to console log the wp javascript object to explorefurther. Things get really interesting down there.

readmore_text_control.active.set( true == show_readmore_setting.get() );

Then, we are showing the “Read More Text” Control only if the “Show Read More Link” Setting returns true. 

The active.set method is responsible for keeping a Control active( visible ) or inactive (hidded) based on a condition. 

readmore_text_control.active.set(true == show_readmore_setting.get());

Simply put, we are keeping the “Read More Text” Control active inside the “Text Options” Section only if “Show Read More Link” Setting returns true. 

We are getting the value of the “Show Read More Link” Setting with the help of get() method attached to the Setting.


show_readmore_setting.bind( function( updated_value_of_show_readmore_setting ) {
    readmore_text_control.active.set( true == updated_value_of_show_readmore_setting );
} );

The value of “Show Read More Link” Setting changes every time we click on the “Show Read More Link” control. 

So, we are repeating the same process of hiding the Control whenever the value of “Show Read More Link” Setting changes with the help of Javascript’s bind() function. 

That’s all! Essentially, this is the JS version of “nd_dosth_hide_readmore_on_condition” Active Callback. We are doing the same thing.

Easy, right?

“Hey, you did not use any jQuery inside the code, is the above jQuery dependent?”

Na! It is not! We used vanilla Javascript.

“Then why did you pass jQuery to the outer function?”

It is just a habit of mine. You can remove it if you want to!

Anyway, if you now go back to the Customize Panel and if you turn off the “Show Read More Link” Control, the “Read More Text” Control gets hidden right away. And vice-versa happens when you turn it back on!

Now that’s what I call improved user experience.

“Yayyyyyyyy! I really love it!”

Do not celebrate! We still did not fix the Site Preview yet!

Fixing the Site Preview 

The “Continue Reading” link is still showing up even when the “Show Read More Link” is turned off. To fix this problem, we have to write a similar piece of Javascript we have coded above.

And we have to enqueue this Javascript using the customize_preview_init action hook because we are dealing with the “Site Preview” portion of the Customize Panel.

So, go back to the customize.php file and put the following code at the end of the file:

/**
 * Registers the Theme Customizer Preview with WordPress.
 */
function nd_dosth_customize_live_preview() {
    wp_enqueue_script(
        'nd-dosth-customize-js',
        get_stylesheet_directory_uri() . '/assets/js/customize.js',
        array( 'jquery', 'customize-preview' ),
        '',
        true
    );
}
add_action( 'customize_preview_init', 'nd_dosth_customize_live_preview' );

This new script depends on the jQuery and Customize Preview script that WordPress ships with. So we are telling WordPress to enqueue them right before our custom script.

Again, we did not create this file yet!

Common, go ahead and create a new file called customize.js inside the assets/js directory. Here is the full path to the file:

/wp-content/themes/nd-dosth/assets/js/customize.js

Next, open up the customize.js file and put the following Code inside it:


(function($){
    /* Show/Hide Read More link inside Site Preview */
    wp.customize( 'nd_dosth_show_readmore', function( value_of_show_readmore_setting ) {
        
        value_of_show_readmore_setting.bind( function( updated_value_of_show_readmore_setting ) {
            if( true == updated_value_of_show_readmore_setting ){
                $('.read-more-link').show();
            } else{
                $('.read-more-link').hide();
            }
        } );
        
    } );
})(jQuery);

Again, nothing much going on in the above code. Whenever we turn on/off the “Show Read More Link” Control in the Customize Panel, the callback function in the above code will get executed. 

And this callback function receives the value of the “Show Read More Link” setting in the form of value_of_show_read_more_setting parameter.

Next, as usual, we are getting the updated value of the value_of_show_read_more_setting parameter using the Javascript’s bind function and based the updated value, we are showing/hiding the “Read More” Link inside the Site Preview portion.

See? It is working as expected. This is a huge user experience boost for users interacting with the Customize Panel.

Sorry but, all this is a big mess up

“What?”

Yep! we messed it up and we brought in a bigger user experience problem in the name of enhancing it.

To reproduce the problem, implement the following steps:

Step 1) Turn off the “Show Read More Link” Control and publish the changes.

Everything will work as expected up and until this point. 

Step 2) Refresh the Customize Panel and find your back to the “Text Options” Panel.

Again, you’ll see the same interface as the above screenshot.

But if now turn on the “Show Read More Link” Control, the “Read More Text” Control will slide down as expected. But, the “Continue Reading” Link in the Site Preview doesn’t show up.

No matter how many times you turn on/off the “Show Read more Link” Control, the “Continue Reading” Link is not going to show up. 

This is happening because, in step 1, we turned off the “Continue Reading” Link and published the changes and WordPress is rendering the Site Preview section using our theme’s template files, right?

The thing is, inside our blog-index.php template file, we are totally omitting the markup of “Continue Reading” Link if the “Show Read More Link” setting is turned off.


<?php if( get_option('nd_dosth_show_readmore', true ) ): ?>
    <a class="read-more-link" href="<?php the_permalink(); ?>">
        <?php echo get_option( 'nd_dosth_readmore_text', __( 'Read More', 'nd_dosth' ) ); ?>
    </a>
<?php endif; ?>

So, if you inspect the blog post markup in the Site Preview Section, there is no “Continue Reading” markup at all.

So, our Javascript code inside the customize.js file is trying to show/hide an HTML element that doesn’t even exist. 

(function($){
    /* Show/Hide Read More link inside Site Preview */
    wp.customize( 'nd_dosth_show_readmore', function( value_of_show_readmore_setting ) {
        
        
value_of_show_readmore_setting.bind( function( updated_value_of_show_readmore_setting ) {
            if( true == updated_value_of_show_readmore_setting ){
                $('.read-more-link').show();
            } else{
                $('.read-more-link').hide();
            }
        } );} );
})(jQuery);

Get it?

Don’t get confused. The problem is only with the Site Preview. If you hit the Publish button and refresh it, you’ll notice that turn on/off the “Show Read more Link” Control is still working as expected.

Here is a fun fact! 

We can not actually bring in the “read-more-link” HTML markup magically by appending some code to the above script. 

Technically, inside the customize.js file, we can only work with HTML markup that is already present inside the Site Preview. For example, we can hide/show elements that are present in the Markup. Not just hide and show, we can edit an HTML element’s background color, text color, etc.

Whatever changes we make using in the above Javascript files are not permanent. They are just temporary. We are writing this Javascript code only to mimic the permanent changes.

So, we can not work on the markup that is not generated. We are using Javascript for enhancing the User Experience but not to magically print markup from the template files.

“I get it! What is the solution now?”

No More Twists!

We can solve this problem if we change the way we are outputting the “read-more-link” element inside our blog-index.php template file.

Currently, we are outputting the “read-more-link” element only if the “Show Read More Link” setting is True.

The solution is, we have to use CSS to hide or Show “read-more-link” element instead of not generating the markup completely if the “Show Read More Link” setting is False.

You’ll understand what I am saying once we implement the solution.

Open up the blog-index.php template file and remove the IF CONDITION around the “read-more-link” HTML element.

<?php if( get_option('nd_dosth_show_readmore', true ) ): ?>
    <a class="read-more-link" href="<?php the_permalink(); ?>">
        <?php echo get_option( 'nd_dosth_readmore_text', __( 'Read More', 'nd_dosth' ) ); ?>
    </a>
<?php endif; ?>

Here is the updated blog-index.php template file:


<div class="blog-post">
    <?php if( is_front_page() || is_single() ): ?>
        <h3><a href="<?php the_permalink(); ?>"><?php the_title(); ?></a></h3>
    <?php else: ?>
        <h2><a href="<?php the_permalink(); ?>"><?php the_title(); ?></a></h2>
    <?php endif; ?>
    <?php if ( has_post_thumbnail() ) :
        $featured_image = wp_get_attachment_image_src( get_post_thumbnail_id( get_the_ID() ), 'dosth-blog-thumbnail' ); ?>
        <div class="blog-post-thumb">
            <a href="<?php the_permalink(); ?>"><img src="<?php echo $featured_image[0]; ?>" alt="" /></a>
        </div>
    <?php endif; ?>
    <?php the_excerpt(); ?>
    <a class="read-more-link" href="<?php the_permalink(); ?>">
        <?php echo get_option( 'nd_dosth_readmore_text', __( 'Read More', 'nd_dosth' ) ); ?>
    </a>
    <?php $categories = get_the_category(); ?>
    <?php if ( ! empty( $categories ) ) : ?>
        <div class="posted-in">
            <span><?php _e( 'Posted In', 'nd_dosth' ); ?></span>
            <a href="<?php echo get_category_link( $categories[0]->term_id ); ?>"> 
                <?php echo $categories[0]->name; ?>
            </a>
        </div>
    <?php endif; ?>
</div>

Now that we have removed the IF Condition around the “read-more-link” HTML element, the link markup will be generated by WordPress even if the nd_dosth_show_readmore Setting is set to false.

Next, add the following Code at the end of the customize.php file:


/**
 * Generate Internal CSS from the values Customize Panel Settings
 */
function nd_dosth_customization_css(){

    $style = '';

    //Get Options from the Customize Panel
    $show_read_more_link = get_option( 'nd_dosth_show_readmore' );

    // Hide ".read-more-link" element if the "Show Read More Link" Control is turned Off
    if( false == $show_read_more_link ){
        $style .= ".read-more-link{display:none}";
    }
    // Remove unnecessary spacing from the styles
    $style = str_replace( array( "\r", "\n", "\t" ), '', $style );

    // Put the final style output together.
    $style = "\n" . '' . "\n";

    // Echo it
    echo $style;
}
add_action( 'wp_head', 'nd_dosth_customization_css' );

Basically, in the above code, we are injecting some dynamic CSS into the header portion of our site using the wp_head() action hook. That’s all.

Let’s break it down.


$style = '';

First of all, we are creating an empty variable. The idea is to append all the dynamic CSS to this variable.


$show_read_more_link = get_option( 'nd_dosth_show_readmore' );

Next, we are getting the value of the nd_dosth_show_readmore Setting.


if( false == $show_read_more_link ){
    $style .= ".read-more-link{display:none}";
}

If the value of nd_dosth_show_readmore Setting is false, we are hiding the “read-more-link” HTML element via CSS.


$style = str_replace( array( "\r", "\n", "\t" ), '', $style ); 

Usually, on a production site, we will be appending quite a bit of dynamic CSS to the $style variable. 

And Removing unnecessary spacing from the $style variable is a good idea. So, we are using str_replace function to remove newlines, carriage returns from the $style variable. 

Simply put, we are compressing the internal CSS we are outputting to the header portion of our site. 


$style = "\n" . '' . "\n";
echo $style;

Finally, we are wrapping our styles inside the <style> tag and echoing the final set of styles to the frontend.

If we test out the “Show Read More Link” Control inside the Customize Panel, everything is finally working as expected.

And that’s pretty much how we improve the user experience of the Customize Panel Options using the “postMessage” transport method.

Now that we know what is right and what is wrong. In the next lesson, we will put this knowledge to good use one last time by allowing the client to edit the color scheme of our site.