Posted on Leave a comment

How to create a Featured Category Slider Widget in WordPress using Owl Carousel

Widgets are an integral part of the WordPress ecosystem and play an important role in the structure and layout of a website. By default, WordPress provides a number of widgets such as Text, Image, Recent Posts, Recent Comments among many others. In normal circumstances, these are enough. But in case you want to go to the deep end and provide custom widgets, WordPress accommodates this requirement with the use of its WP_Widget class. By extending this class, we can create and infinite number of custom widgets suiting our needs and requirements. In this article, we are going to take a look at how to create Featured Category Slider Widget in WordPress using Owl Carousel.

Setting up the widget

First of all we need to set up the widget so that it appears in Appearance > Widgets and we are able to set it in one of our sidebars. First of all, in the theme directory, create a new file for including the PHP code for the new widget. You can set it anywhere, but for the sake of this article, i have put it in /inc folder and named it category-slider.php.
Now we need to include it in the theme. Go to functions.php, at the end of the file, add the following code –

require get_template_directory() . '/inc/category-slider.php';

This includes the category-slider.php file in the theme. Now, we need to write the PHP code for the widget in the theme. I have already written an article on how to create a custom widget in this article. Do check that out. Also, since I have gone in detail about how to create a widget in this article, I will not be going in detail in this one.

Now, coming to the current article, add the following code to category-slider.php . I’ll explain it in a bit –

<?php
// Register and load the widget
function mytheme_cat_slider_widget() {
    register_widget( 'mytheme_cat_slider' );
}
add_action( 'widgets_init', 'mytheme_cat_slider_widget' );

// Creating the widget
class mytheme_cat_slider extends WP_Widget {

    function __construct() {
        parent::__construct(

// Base ID of your widget
            'mytheme_cat_slider',

// Widget name will appear in UI
            esc_html__('Category Slider', 'mytheme'),

// Widget description
            array( 'description' => esc_html__( 'Display posts from a particular category in the form of a Slider.', 'mytheme' ), )
        );
    }

// Creating widget front-end

    public function widget( $args, $instance ) {

        $title = apply_filters( 'widget_title', empty( $instance['title'] ) ? '' : $instance['title'], $instance, $this->id_base );
        $post_count             = isset( $instance['post_count'] ) ? $instance['post_count'] : 4;
        $category_slider 		= isset( $instance['category_slider'] ) ? $instance['category_slider'] : 0;
        
        $export	= [
	        'id'	=>	$this->id
        ];
        
        wp_localize_script('mytheme-custom-js', 'cat_slider_' . $this->number, $export);
        
                echo $args['before_widget'];
                if ( ! empty( $title ) )
                    echo $args['before_title'] . $title . $args['after_title'];
            ?>

            <?php
            	$widget_args = array(
	            	'cat'					=>	$category_slider,
	            	'ignore_sticky_posts'	=>	true,
	            	'posts_per_page'		=>	$post_count
            	);
            	
            	$widget_query	=	new WP_Query($widget_args);
            	
            	if ( $widget_query->have_posts() ) : ?>
            		<div class="cat-slider owl-carousel owl-theme">
	            	<?php
	            		while ($widget_query->have_posts() ) : $widget_query->the_post();
	            		?>
	            		<div class="cat-slide">
		            		<div class="slide-image">
			            		<?php if ( has_post_thumbnail() ): ?>
									<a href="<?php the_permalink(); ?>"><?php the_post_thumbnail('mytheme_slide'); ?></a>
								<?php
								else :
								?>	<a href="<?php the_permalink(); ?>"><img class="wp-post-image" src="<?php echo esc_url(get_template_directory_uri() . '/assets/images/ph-slide-cats.svg'); ?>"></a>
								<?php endif; ?>
							</div>
							<div class="slide-title">
								<?php the_title( '<h3 class="entry-title"><a href="' . esc_url( get_permalink() ) . '">', '</a></h3>' ); ?>
							</div>
						</div>
						<?php
						endwhile; ?>
					</div>
				<?php
				endif;
				wp_reset_postdata();
				
	echo $args['after_widget'];

    }

// Widget Backend
    public function form( $instance ) {

        /* Set up some default widget settings. */
        $defaults = array(
        	'title'              => esc_html__( 'Featured Posts', 'mytheme' ),
			'post_count'         => 4,
			'category_slider'    => 0
        );
        $instance = wp_parse_args( (array) $instance, $defaults );
        ?>

        <p>
            <label for="<?php echo $this->get_field_id( 'title' ); ?>"><?php _e( 'Title:', 'mytheme' ); ?></label>
            <input class="widefat" id="<?php echo $this->get_field_id( 'title' ); ?>" name="<?php echo $this->get_field_name( 'title' ); ?>" type="text" value="<?php echo esc_attr( $instance['title'] ); ?>" />
        </p>


        <h3><?php esc_html_e('Slider', 'mytheme'); ?></h3>

        <p>
            <label for="<?php echo $this->get_field_id( 'post_count' ); ?>"><?php _e( 'Number of Posts:', 'mytheme' ); ?></label>
            <input id="<?php echo $this->get_field_id( 'post_count' ); ?>" name="<?php echo $this->get_field_name( 'post_count' ); ?>" type="number" value="<?php echo esc_attr( $instance['post_count'] ); ?>" />
        </p>

        <p>
			<label for="<?php echo esc_attr( $this->get_field_id( 'category_slider' ) ); ?>"><?php _e('Category for Slider:', 'mytheme'); ?></label>
			<select id="<?php echo esc_attr( $this->get_field_id( 'category_slider' ) ); ?>" name="<?php echo esc_attr( $this->get_field_name( 'category_slider' ) ); ?>">
				<option value="0" <?php if ( !$instance['category_slider'] ) echo 'selected="selected"'; ?>><?php _e('--None--', 'mytheme'); ?></option>
				<?php
				$categories = get_categories(array('type' => 'post'));

				foreach( $categories as $cat ) {
					echo '<option value="' . esc_attr( $cat->cat_ID ) . '"';

					if ( $cat->cat_ID == $instance['category_slider'] ) echo  ' selected="selected"';

					echo '>' . esc_html( $cat->cat_name . ' (' . $cat->category_count . ')' );

					echo '</option>';
				}
				?>
			</select>
		</p>

        <?php
    }


    // Updating widget replacing old instances with new
    public function update( $new_instance, $old_instance ) {
        $instance = array();
        $instance['title']      =   ( ! empty( $new_instance['title'] ) ) ? strip_tags( $new_instance['title'] ) : '';
        $instance['post_count']         =   ( ! empty( $new_instance['post_count'] ) ) ? (int)$new_instance['post_count'] : 4;
        $instance['category_slider']    =   ( ! empty( $new_instance['category_slider'] ) ) ? (int)$new_instance['category_slider'] : 0;
        return $instance;
    }
} // Class post author ends here

In this code, I am registering a widget with the id mytheme_cat_slider by extending the WP_Widget class. The name, id and description of the widget are defined in the constructor of the widget class. The back-end of the Widget ( the fields that appear in Appearance > Widgets ) are defined in the form function while the front-end is present in the widget function.

In the form function, we define the variables that control the title of the widget, the number of posts in the slider and the category to be used for the slider making use of the appropriate checks.

In the update function, we store any change in the variables. Finally, the widget function, we render the output of the widget. I believe the readers of this posts are at least an intermediate level WordPress developers, so I’ll not go in details of the code but I need to point out one thing. In the widget function, we have used the wp_localize_script function. This function is used to transmit PHP variables as an object to a JS file.In our case, we define mytheme-custom-js as our js file. We need JS to render the Owl Carousel later.

Creating the JS file

We need to enqueue the file that we have used in the wp_localize_script function. We create a file named custom.js and place it in js folder in the theme directory. After creating the file, add the following code to functions.php –

function my_theme_enqueue_scripts() {
    wp_enqueue_script('mytheme_custom_js', get_template_directory_uri() . '/js/custom.js', array('jquery'), NULL, false);
}
add_action('wp_enqueue_scripts', 'my_theme_enqueue_scripts');

In this code, we enqueued the JS file that will incorporate our JS code. note that the first parameter of the wp_localize_script function is same as the ID of the enqueued script. This is how wp_localize_script knows where to transmit the variables object.

Also, we need to enqueue Owl Carousel CSS and JS files. We first need to download them from their official page. We need two files from the downloaded folder. One is the CSS file in dist/assets folder (owl.carousel.min.css), the other in assets folder(owl.carousel.min.js). Place both of these files in the assets/owl folder and add the following code to my_theme_enqueue_scripts() function in functions.php

function my_theme_enqueue_scripts() {

    wp_enqueue_style('mytheme_owl_css', get_template_directory_uri() . '/assets/owl/owl.carousel.min.css', array(), NULL, false);

    wp_enqueue_script('mytheme_owl_js', get_template_directory_uri() . '/assets/owl/owl.carousel.min.js', array(), NULL, false);

    wp_enqueue_script('mytheme_custom_js', get_template_directory_uri() . '/js/custom.js', array('jquery'), NULL, false);
}
add_action('wp_enqueue_scripts', 'my_theme_enqueue_scripts');

Understanding what is happening

With all the code here, we need to understand what is happening. In the widget code, the variables get transmitted to custom.js in the form of an object named ‘cat_slider_{id}’ with ID being different for every instance of widget created. This is important as during initialization of slider, as we do not want one slider having multiple controls and vice-versa. In this object, we pass the ID of the widget. Now, the only thing that’s left to do is initializing the slider.

Initialize the Slider

In custom.js, add the following code-

var catSliders = [];

for (catSlider in window) {
    if ( catSlider.indexOf("cat_slider") != -1 ) {
	    catSliders.push( window[catSlider] );
    }
};
catSliders.forEach( function( item ) {
    var slider = jQuery("#" + item.id).find('.cat-slider');
    slider.owlCarousel({
	    items: 1,
	    loop: true,
	    autoplay: true,
	    dots: false,
	    nav: true
    });
});

In this code, we have created an array variable named catSliders. Initially this array is empty. On iterating through the window object, the transmitted widget objects are pushed in the catSliders array.

We, then iterate over the catSliders array to initialize the Owl Carousel. In this example, i have kept the settings for the slider constant for all instances. If you want to make them different for every slider instance, they’ll need to be included in the widget and transmitted to custom.js via $exports.

So, that’s about it! Now, when you add the Widget in any sidebar and add number of posts and the category to the widget, the slider will be enabled in the front-end. This is an advanced level article, so if you feel confused at any place, just drop it in the comments. And if you’re a pro, please suggest some improvements to this. There is always room for more efficient code.

Leave a Reply

Your email address will not be published. Required fields are marked *