Creating a Widget

Widgets Bundle > Getting Started> Creating a Widget

A Widgets Bundle widget is a folder with a PHP file that declares the widget, a template that outputs it and an optional LESS stylesheet. The Widgets Bundle builds the widget's form from the fields you declare, then saves and renders the widget for you.

Registering a Widgets Folder

The siteorigin_widgets_widget_folders filter registers a folder of your own widgets, so you can keep them apart from the SiteOrigin widgets:

<?php
function add_my_awesome_widgets_collection( $folders ) {
    $folders[] = plugin_dir_path( __FILE__ ) . 'widgets/'; // An absolute path. The slash at the end is required.
    return $folders;
}
add_filter( 'siteorigin_widgets_widget_folders', 'add_my_awesome_widgets_collection' );

The Widgets Bundle looks for PHP files in each subfolder of a registered folder. It lists every file whose metadata header has a Widget Name field as a widget that users can activate and use in widget areas, Page Builder and the Block Editor.

The extend-widgets-bundle plugin in our so-dev-examples repository is a standard WordPress plugin that uses this filter to add its extra-widgets folder.

Naming the Widget Folder

Create a folder for your widget, and a PHP file inside it with the same name. Follow the WordPress naming best practices for the file and folder names.

Adding the Metadata Header

Start the PHP file with a metadata header. The Widgets Bundle uses the header to find files that contain a widget, and it skips any file without a Widget Name field. The other fields are optional, and they give users more information about the widget and its author:

<?php
/*
Widget Name: Hello world widget
Description: An example widget which displays 'Hello world!'.
Author: Me
Author URI: http://example.com
Documentation: http://example.com/hello-world-widget-docs
*/

Writing the Widget Class

Your widget class extends the SiteOrigin_Widget base class. SiteOrigin_Widget builds on the WordPress Widgets API, so the class needs a constructor that describes the widget. Declare the form fields in a get_widget_form() method, as the example does. Passing $form_options to the constructor also works.

Register the class with siteorigin_widget_register(), passing the widget ID, the path of the widget file and the class name:

class Hello_World_Widget extends SiteOrigin_Widget {
    function __construct() {
        // Here you can do any preparation required before calling the parent constructor, such as including additional files or initializing variables.
        // Call the parent constructor with the required arguments.
        parent::__construct(
            // The unique id for your widget.
            'hello-world-widget',
            // The name of the widget for display purposes.
            __( 'Hello World Widget', 'hello-world-widget-text-domain' ),
            // The $widget_options array, which is passed through to WP_Widget.
            // It has a couple of extras like the optional help URL, which should link to your sites help or support page.
            array(
                'description' => __( 'A hello world widget.', 'hello-world-widget-text-domain' ),
                'help'        => 'http://example.com/hello-world-widget-docs',
            ),
            // The $control_options array, which is passed through to WP_Widget
            array(),
            // We set $form_options using the get_widget_form method below.
            false,
            // The $base_folder path string.
            plugin_dir_path( __FILE__ )
        );
    }
    public function get_widget_form() {
        return array(
            'text' => array(
                'type'    => 'text',
                'label'   => __( 'Hello world! goes here.', 'hello-world-widget-text-domain' ),
                'default' => 'Hello world!',
            ),
        );
    }
}
siteorigin_widget_register( 'hello-world-widget', __FILE__, 'Hello_World_Widget' );

The widget now appears in the list at Plugins > SiteOrigin Widgets. New widgets start inactive, so activate the Hello World Widget there before you use it. Its form has a text field with the default text "Hello world!", which users can edit and save. The widget shows nothing on the front end until it has a template.

Adding a Template

The template outputs the widget. The Widgets Bundle looks for tpl/default.php in your widget folder. Override get_template_name() to use another template, and return the template's file name without .php. Override get_template_dir() to use another folder, and return the folder's path relative to the widget class file, without leading or trailing slashes:

function get_template_name( $instance ) {
    return 'hello-world-template';
}
function get_template_dir( $instance ) {
    return 'hw-templates';
}

The Hello World Widget's files are laid out like this:

hello-world-widget/
├── assets/
│   └── banner.svg
├── styles/
│   └── hello-world-widget-style.less
├── tpl/
│   └── hello-world-widget-template.php
└── hello-world-widget.php

The Hello World Widget's template outputs the widget's text:

<div>
    <?php echo wp_kses_post( $instance['text'] ); ?>
</div>

The widget now shows its text on the front end.

Adding Styles

The Widgets Bundle loads styles/default.less from your widget folder. Override get_style_name() to use another LESS stylesheet in the styles folder, and return the stylesheet's file name without .less. LESS Stylesheets explains how the Widgets Bundle uses LESS.

function get_style_name( $instance ) {
    return 'my-widget-styles';
}

Adding a Banner Image

Each widget has a banner in the list at Plugins > SiteOrigin Widgets. Save your banner as assets/banner.svg in your widget folder, or set its URL with the siteorigin_widgets_widget_banner filter. This example sits in my-awesome-widget.php, outside the class. If you put the code in another file, change the image path to match:

function my_awesome_widget_banner_img_src( $banner_url, $widget_meta ) {
    if ( $widget_meta['ID'] == 'my-awesome-widget' ) {
        $banner_url = plugin_dir_url( __FILE__ ) . 'images/awesome_widget_banner.svg';
    }
    return $banner_url;
}
add_filter( 'siteorigin_widgets_widget_banner', 'my_awesome_widget_banner_img_src', 10, 2 );