What is the correct way to build a widget using OOP

I am working on a simple search form widget, with a built in autocomplete capability (You can download the current version here). The plugin is working, but I am currently rewriting all the code using OOP. One of the problems I came across was the fact the a WordPress Widget is already a part of the WP_Widget class.
I can divide the code into 2 classes. The first one loads all the scripts and css, and initializes the widget. Here is the outline of the code:

class wdSearchForm {

        public function __construct() {
            // Action hook to load widget
            // Register and enqueue styles
            // Register and enqueue scripts
        }

        // register widget in WordPress so that it is available under the widgets section
        public function wd_searchform() {
            register_widget( 'wd_searchform' );
        }
}

And here is the outline to the widget class:

Read More
class wd_searchform extends WP_Widget {

    // Constructor
    function wd_searchform() {

    }

    // The widget itself
    function widget( $args, $instance ) {
        // The widget code
    }

    //Update the widget 
    function update( $new_instance, $old_instance ) {
        // Update code
    }

    function form( $instance ) {
        //Set up widget settings.
    }
}

I would like to combine the two, in order to use wp_localize_script and load the script with the widget options. How should I do that? Any suggestions are welcome, even if you’ll tell me i’m totally in the wrong direction…

Related posts

Leave a Reply

2 comments

  1. You can simply put your init code within the constructor of the class. For example:

    class myWidget extends WP_Widget{
    
        function myWidget(){
           // Init code here
        }
    
        function widget( $args, $instance ) {
           // The widget code
           wp_enqueue_script(...);
           wp_enqueue_style(...);
    
       }
    
       // Over methods...
    
    }
    
    register_widget('myWidget');
    

    My preference is to actually put the enqueue calls within the shortcode handling function to avoid the overhead and potential conflicts associated with loading JavaScript and stylesheets that aren’t being used on a given page.

  2. Your code is PHP4 style. PHP4 styled code should not be used anymore. And just putting some functions inside a class construct is not OOP. If you want to write reusable code, separate your code.

    For example:

    class Widget_Setup
    {
        public $widget_class  = '';
        public $admin_styles  = array();
        public $admin_scripts = array();
        public $front_styles  = array();
        public $front_scripts = array();
    
        public $script_defaults = array(
            'handle'    => '',
            'src'       => '',
            'deps'      => array(),
            'version'   => false,
            'in_footer' => false
        );
    
        public $style_defaults = array(
            'handle'   => '',
            'src'      => '',
            'deps'     => array(),
            'version'  => false,
            'media'    => 'all'
        );
    
        public function __construct( $widget_class = '', $admin_styles = array(), $admin_scripts = array(), $front_styles = array(), $front_scripts = array() ) {
    
            $this->widget_class  = $widget_class;
            $this->admin_styles  = $admin_styles;
            $this->admin_scripts = $admin_scripts;
            $this->front_styles  = $front_styles;
            $this->front_scripts = $front_scripts;
    
            add_action( 'admin_print_styles',    array( $this, 'add_styles' ) );
            add_action( 'admin_enqueue_scripts', array( $this, 'add_scripts' ) );
            add_action( 'wp_enqueue_scripts',    array( $this, 'add_styles' ) );
            add_action( 'wp_enqueue_scripts',    array( $this, 'add_scripts' ) );
    
            if( ! empty( $this->widget_class ) )
                add_action( 'widgets_init', array( $this, 'register_widget' ) );
    
        }
    
        public function register_widget() {
    
            register_widget( $this->widget_class );
    
            return true;
    
        }
    
        public function add_styles() {
    
            $styles = ( is_admin() ) ?
                $this->admin_styles : $this->front_styles;
    
            if( empty( $styles ) )
                return false;
    
            foreach( $styles as $style ) {
    
                $style = wp_parse_args( $style, $this->style_defaults );
    
                wp_enqueue_style(
                    $style['handle'],
                    $style['src'],
                    $style['deps'],
                    $style['version'],
                    $style['media']
                );
    
            }
    
            return true;
        }
    
        public function add_scripts() {
    
            $scripts = ( is_admin() ) ?
                $this->admin_scripts : $this->front_scripts;
    
            if( empty( $scripts ) )
                return false;
    
            foreach( $scripts as $script ) {
    
                $script = wp_parse_args( $script, $this->script_defaults );
    
                wp_enqueue_script(
                    $script['handle'],
                    $script['src'],
                    $script['deps'],
                    $script['version'],
                    $script['media']
                );
    
            }
    
            return true;
        }
    
    }
    

    This class can be reused for every widget. The idea behind OOP is reusing your code by writing data constructs with additional function. Not using class constructs because somebody say it is good style.

    The class could be used like this:

    class MyAwesomeWidget extends WP_Widget
    {
    
        const TEXTDOMAIN = 'widget_textdomain';
    
        public function __construct() {
    
            parent::__construct(
    
                'widget-name-id',
                __( 'Widget Name', self::TEXTDOMAIN ),
                array(
                    'classname'   =>    __CLASS__,
                    'description' =>    __( 'Short description.', self::TEXTDOMAIN )
                )
            );
    
            $admin_style = array(
                array( 'handle' => 'somehandle', 'src' => 'path/to/source' ),
                array( 'handle' => 'someotherhandle', 'src' => 'path/to/source' ),
            );
    
            $admin_scripts = array(
                array( 'handle' => 'scrpthandle', 'src' => 'path/to/source', 'deps' => array( 'jquery') ),
            );
    
            $front_styles = array(
                array( 'handle' => 'frontstyle', 'src' => 'path/to/src' ),
            );
    
            new Widget_Setup( __CLASS__, $admin_style, $admin_scripts, $front_styles );
        }
    
        public function widget( $instance, $args ) {}
    
        public function update( $new_instance, $old_instance ) {}
    
        public function form( $instance ) {}
    
    }