WooCommerce reviews + tutorials
  1. Building Your First WooCommerce Extension
  2. Hooking into WooCommerce Actions
  3. How to Create a WooCommerce Widget
  4. Widgets, Part Deux: Create a Smart WooCommerce Widget
  5. Add Plugin Settings to WooCommerce, Part 1
  6. Add Plugin Settings to WooCommerce, Part 2
  7. WooCommerce Class Members Example: Create a WooCommerce Upsell Shortcode
  8. How to Create a Simple WooCommerce Payment Gateway

Today we’re continuing our series on building your first WooCommerce plugin with an article on how to create a WooCommerce widget for your store.

Widgets and shortcodes are great tools to let users output some information on the frontend of their eCommerce site, and they’re fairly easy to build and include as part of your plugin. We’ve already written about creating a shortcode for your site, so today we’ll focus on building a basic widget, with a more advanced widget tutorial to follow.

Our basic widget will always be displayed, and can be used on any widget area of the site.

WooCommerce Widget Components

There are a few basic pieces to any widget, which the WordPress codex and details on using register_widget can give you an overview of. However, these don’t explain in detail what each function in the widget does, so we’ll take a look at each in more detail.

If you’re looking for a sample to follow, the core text widget is a good example.

The Widget Class

The main piece of your widget will be creating a class that extends the WP_Widget class. This will let you extend all of the basic components of a widget, but change the pieces you need to, such as the title and what’s output on the frontend. There are 4 functions that this class must contain:

public function __construct: This function will “set up” your widget, and there are helpful details in the WP_Widget docs. You can optionally set options, then instantiate the widget. The general format for instantiating your widget:

parent::__construct( 'Widget_Classname', __( 'Widget Title (for users)', 'textdomain' ), $options );

Here’s what our shipping widget will use:

public function __construct() {
    
    // set widget options
    $options = array(
        'classname'   => 'widget_wc_active_shipping', // CSS class name for this widget
        'description' => __( 'Displays a list of active shipping methods for your shop.', 'wc-active-shipping-widget' ),
    );
        
    // instantiate the widget -- use your widget's class as the first param here
    parent::__construct( 'WC_Active_Shipping_Widget', __( 'WooCommerce Active Shipping Methods', 'wc-active-shipping-widget' ), $options );
}

public function widget: This function will accept 2 parameters: $args and $instance. The $instance is the array of settings for the widget instance, while $args is the array of display arguments (such as before_title, after_title, etc), which are typically used by themes to format widgets, so you should include these.

The basic structure of this function should look something like this to include the display arguments properly:

public function widget( $args, $instance ) {
        
    // get the widget's configured title
    $title = $instance['title'];
        
    echo $args['before_widget'];
        
    if ( $title ) {
        echo $args['before_title'] . $title . $args['after_title'];
    }
        
    // This is where you add what your widget should output 
    // Add your widget's magic here
        
    echo $args['after_widget'];
}

For our shipping widget, we’ll output a list of methods here. We’ll get the shipping methods (from another function that we’ll address in a bit), and if there are methods to show, we’ll show them in a list:

public function widget( $args, $instance ) {
    // Get the active methods and bail if there are none
    $methods = $this->get_active_shipping_methods();
    if ( empty( $methods ) ) {
        return;
    }
        
    // get the widget configuration
    $title = $instance['title'];
    $added_text = $instance['text'];
        
    echo $args['before_widget'];
        
    if ( $title ) {
        echo $args['before_title'] . $title . $args['after_title'];
    }
        
    // Show the additional text if set
    if ( $added_text ) {
        echo '<p>' . wp_kses_post( $added_text ) . '</p>';
    }

    // Start active shipping method list    
    echo '<ul>';
        
    foreach ( $methods as $method ) {
        echo '<li>' . $method . '</li>';
    }
        
    echo '</ul>';
    // End shipping method list
    
    echo $args['after_widget'];
}

public function update: This function handles updating our widget instance with any settings configured by the user. For example, this can let the user set the widget title, or some other part of the widget (such as display text). This function accepts the old settings for the widget, then updates them with the new settings entered by the user.

The general format takes every setting from the $instance (which we’ll create next) and updates them with whatever the user has entered. You’ll need to update each setting individually.

public function update( $new_instance, $old_instance ) {
    
    $instance['setting1'] = strip_tags( $new_instance['setting1'] );
    $instance['setting2'] = strip_tags( $new_instance['setting2'] );
    return $instance;
}

Our shipping plugin will look like this:

public function update( $new_instance, $old_instance ) {
    
    $instance['title'] = strip_tags( $new_instance['title'] );
    $instance['text'] = strip_tags( $new_instance['text'] );    
    return $instance;
}

public function form: The final function needed to create our widget is the form for settings, which passes in the $instance array (the settings array). This will include a label and field for any setting / field the widget should contain. This can be the widget title for the user to set, and any other field, such as textareas, selects, or checkboxes.

Our shipping method widget will use two fields in its form: “title” and “text” for additional text:

public function form( $instance ) {
    ?>
    <p>
        <label for="<?php echo esc_attr( $this->get_field_id( 'title' ) ); ?>"><?php _e( 'Title', 'wc-active-shipping-widget' ) ?>:</label>
        <input type="text" class="widefat" id="<?php echo esc_attr( $this->get_field_id( 'title' ) ); ?>" name="<?php echo esc_attr( $this->get_field_name( 'title' ) ); ?>" value="<?php echo esc_attr( isset( $instance['title'] ) ? $instance['title'] : '' ); ?>" />
    </p>
        
    <p>
        <label for="<?php echo esc_attr( $this->get_field_id( 'text' ) ); ?>"><?php _e( 'Additional text', 'wc-active-shipping-widget' ) ?>:</label>
        <textarea class="widefat" rows="3" cols="20" id="<?php echo esc_attr( $this->get_field_id( 'text' ) ); ?>" name="<?php echo esc_attr( $this->get_field_name( 'text' ) ); ?>"><?php echo esc_textarea( $instance['text'] ); ?></textarea>     </p>
    <?php
}

Once you’ve added each of these functions to your widget, you can end that class, and now all we have to do is register the widget.

Registering the WooCommerce Widget

In order to add your widget to your site, you’ll need to register it, hooking into widgets_init to do so. This is the easy part 🙂 — register the widget using your widget’s class name, and hook this into widgets_init:

function wc_active_shipping_register_widget() {
    register_widget( 'WC_Active_Shipping_Widget' );
}
add_action( 'widgets_init', 'wc_active_shipping_register_widget' );

Congrats, your widget is done!

Getting WooCommerce Shipping Methods

Since our widget is getting some information from WooCommerce, we need a function to get this information. While a simple widget that just outputs static text wouldn’t need this step, since we have to pull the active shipping methods from WooCommerce, we’re going to add a function to get them.

We’ll get all of the active shipping methods in the shop and add this function to our widget class. We’ll find some help in the WC_Shipping class, as we’ll need to load the available shipping methods and see which ones are active.

The load_shipping_method function is necessary to do so. Shipping methods won’t be loaded already, so we’ll need to load all methods and then check them to see which are enabled.

function get_active_shipping_methods() {

    $shipping_methods = WC()->shipping->load_shipping_methods();
    $active_methods = array();  

    foreach ( $shipping_methods as $id => $shipping_method ) {
        // Only get enabled shipping methods and push them into our array
        if ( isset( $shipping_method->enabled ) && 'yes' === $shipping_method->enabled ) {
            $method_title = $shipping_method->title;
            // Append a tag to international delivery in case the name doesn't indicate it
            if ( 'international_delivery' === $id ) {
                $method_title .= ' (International)';
            }
            array_push( $active_methods, $method_title );
        }
    }
    return $active_methods;
}

This is the method I called in my widget class previously to get the WooCommerce shipping methods, which I then looped through and put into my list.

Completed WooCommerce Widget

Now we’ll put all of these steps together into a finished piece of code. Our WooCommerce widget has two settings for title and additional text, which the user can adjust:

WooCommerce Widget in use

This widget will output the title, additional text, and the list of active shipping methods in the shop using the display label set in WooCommerce:

WooCommerce Widget Displayed

The full code is available here: WooCommerce Active Shipping Methods Widget

If you’d like to install this WooCommerce widget as a plugin, you can download the zip and upload it to your site:

Published by Nik McLaughlin

You can find Nik around the WP space, on LinkedIn, or on his personal blog.

3 Comments

  1. Hey, this plugin is just what I was looking for, although I can’t get it to work with woocommerce’s storefront theme, any ideas on how to make it compatible?

  2. Nice widget any way to select shipping method via widget and then post that to the cart page and then widget?

Hmm, looks like this article is quite old! Its content may be outdated, so comments are now closed.