Category: Tutorials
This article also touches on: Object-Oriented Programming
Blurbette Plugin: Widget
Creating a widget is very simple, because WordPress provides a WP_Widget class you can simply extend and define. Four methods are required:
- __construct(): the constructor which simply defines some strings and calls the parent method,
- form(): presents the draggable widget form in the admin panel,
- update(): operates when the form is updated,
- widget(): performs the output in the sidebar.
I’ll discuss each of the four methods one at a time:
<?php class WPCX_Blurbette_Widget extends WP_Widget { public function __construct() { $widget_ops = array( 'classname' => 'wpcx_blurbettes', 'description' => __( 'Display a Blurbette', WPCX_Blurbette_Def::TEXT_DOMAIN ) ); parent::__construct( 'wpcx_blurbette_widget', __( 'Blurbette', WPCX_Blurbette_Def::TEXT_DOMAIN ), $widget_ops ); }
The parent::__construct() method expects, in order: the Base ID, the displayed Title, and an array containing a unique classname and the description.
Next, the form() method:
public function form( $instance ) { $instance = wp_parse_args( (array) $instance, array( 'title' => '', 'blurbette_id' => null ) ); $title = esc_attr( $instance['title'] ); $bbt_id = $instance['blurbette_id']; $drop_ops = WPCX_Blurbette_Def::get_blurbettes_pairs( 'widget' ); ?> <p><label><?php _e( 'Title:', WPCX_Blurbette_Def::TEXT_DOMAIN ); ?><input class="widefat" type="text" id="<?php echo $this->get_field_id( 'title' ); ?>" name="<?php echo $this->get_field_name( 'title' ); ?>" value="<?php echo $title; ?>" /> </label></p> <p><label for="<?php echo $this->get_field_id( 'blurbette_id' ); ?>"><?php _e( 'Blurbette:', WPCX_Blurbette_Def::TEXT_DOMAIN ); ?></label> <select id="<?php echo $this->get_field_id( 'blurbette_id' ); ?>" name="<?php echo $this->get_field_name( 'blurbette_id' ); ?>"><option value=""><?php _e( 'Choose...', WPCX_Blurbette_Def::TEXT_DOMAIN ); ?></option> <?php foreach ( ( array ) $drop_ops['opts'] as $dop ): ?> <option value="<?php echo esc_attr( $dop['ID'] ); ?>" <?php echo selected( $dop['ID'], $bbt_id ); ?>><?php echo esc_html( substr( $dop['label'], 0, 50 ) ); ?></option> <?php endforeach; ?> </select> </p> <?php }
This outputs a simple two-element form, the title input text field, and a blurbette_id dropdown selector. The WP_Widget class adds other things like a Submit button, and Javascript controls for deleting, closing and dragging.
Also, it provides methods like get_field_id() and get_field_name() which I can use herein. They turn my basic name and id into unique ones, properly formatted for form processing.
Next, the update() method:
public function update( $new_instance, $old_instance ) { $instance = $old_instance; $instance['title'] = strip_tags( $new_instance['title'] ); $instance['blurbette_id'] = $new_instance['blurbette_id']; return $instance; }
As you can see, the WP_Widget class makes this part very simple; I simply set elements for an $instance variable, corresponding to my form names above, and return it. Available are the $old_instance and $new_instance arrays for reference.
Lastly, the widget() method:
public function widget( $args, $instance ) { if ( empty( $instance['blurbette_id'] ) ) return; $title = apply_filters( 'widget_title', $instance['title'], $instance, $this->id_base ); if ( WPCX_Blurbette_Def::check_availability( $instance['blurbette_id'], 'widget' ) ): echo $args['before_widget']; if ( ! empty( $title ) ): echo $args['before_title'] . $title . $args['after_title']; endif; echo '<div class="textwidget blurbettewidget">', PHP_EOL; echo do_shortcode( '[blurbette id="' . $instance['blurbette_id'] . '" context="widget"]' ); echo '</div>', PHP_EOL; echo $args['after_widget']; endif; } } // end class WPCX_Blurbette_Widget
WordPress calls the widget method on a custom class, when outputting the custom widget in a sidebar. It passes:
- $args, an array defined in a theme via the register_sidebar() function,
- $instance, an array containing the unique elements defined in form and update.
In this method, I’ve chosen to bail if for some reason the blurbette_id is blank. Also, only output if the WPCX_Blurbette_Def::check_availability() method (still just a placeholder) returns true. Even though the form() checks before making the Blurbette available in the dropdown, a user might later update a Blurbette’s availability without updating the widget.
Notice I’ve chosen to wrap in a <div> element with a textwidget class name, which is WordPress’ builtin class for text widgets; also an additional blurbettewidget class name. A theme is likely to define a stylesheet for a textwidget, so it makes sense to apply that definition here. Adding the additional blurbettewidget gives a designer a chance to customize further.
It’s worth pointing out: output is handled by invoking the shortcode, so any changes made in that class needn’t be re-coded here. Note also, I’ve made use of the extra context="widget" attribute of the shortcode, so output will obey that restriction if defined by the user.
Activating
All that’s left is to modify WPCX_Blurbette_Registry to activate the new widget. Activation is done with WordPress’ register_widget() function, which must be performed at the widgets_init action hook. So, define a new method within the WPCX_Blurbette_Registry class:
public function register_widget() { register_widget( 'WPCX_Blurbette_Widget' ); }
… and hook it within WPCX_Blurbette_Registry’s __construct() method:
function __construct() { spl_autoload_register( array( $this, 'class_autoloader' ) ); WPCX_Blurbette_Def::do_all_hooks(); WPCX_Blurbette_Shortcode::do_all_hooks(); add_action( 'widgets_init', array( $this, 'register_widget' ) ); add_action( 'plugins_loaded', array( $this, 'instantiate_the_rest' ) ); }
Recapping the code
Here’s the entire WPCX_Blurbette_Widget class:
<?php class WPCX_Blurbette_Widget extends WP_Widget { public function __construct() { $widget_ops = array( 'classname' => 'wpcx_blurbettes', 'description' => __( 'Display a Blurbette', WPCX_Blurbette_Def::TEXT_DOMAIN ) ); parent::__construct( 'wpcx_blurbette_widget', __( 'Blurbette', WPCX_Blurbette_Def::TEXT_DOMAIN ), $widget_ops ); } public function form( $instance ) { $instance = wp_parse_args( (array) $instance, array( 'title' => '', 'blurbette_id' => null ) ); $title = esc_attr( $instance['title'] ); $bbt_id = $instance['blurbette_id']; $drop_ops = WPCX_Blurbette_Def::get_blurbettes_pairs( 'widget' ); ?> <p><label><?php _e( 'Title:', WPCX_Blurbette_Def::TEXT_DOMAIN ); ?><input class="widefat" type="text" id="<?php echo $this->get_field_id( 'title' ); ?>" name="<?php echo $this->get_field_name( 'title' ); ?>" value="<?php echo $title; ?>" /> </label></p> <p><label for="<?php echo $this->get_field_id( 'blurbette_id' ); ?>"><?php _e( 'Blurbette:', WPCX_Blurbette_Def::TEXT_DOMAIN ); ?></label> <select id="<?php echo $this->get_field_id( 'blurbette_id' ); ?>" name="<?php echo $this->get_field_name( 'blurbette_id' ); ?>"><option value=""><?php _e( 'Choose...', WPCX_Blurbette_Def::TEXT_DOMAIN ); ?></option> <?php foreach ( ( array ) $drop_ops['opts'] as $dop ): ?> <option value="<?php echo esc_attr( $dop['ID'] ); ?>" <?php echo selected( $dop['ID'], $bbt_id ); ?>><?php echo esc_html( substr( $dop['label'], 0, 50 ) ); ?></option> <?php endforeach; ?> </select> </p> <?php } public function update( $new_instance, $old_instance ) { $instance = $old_instance; $instance['title'] = strip_tags( $new_instance['title'] ); $instance['blurbette_id'] = $new_instance['blurbette_id']; return $instance; } public function widget( $args, $instance ) { if ( empty( $instance['blurbette_id'] ) ) return; $title = apply_filters( 'widget_title', $instance['title'], $instance, $this->id_base ); if ( WPCX_Blurbette_Def::check_availability( $instance['blurbette_id'], 'widget' ) ): echo $args['before_widget']; if ( ! empty( $title ) ): echo $args['before_title'] . $title . $args['after_title']; endif; echo '<div class="textwidget blurbettewidget">', PHP_EOL; echo do_shortcode( '[blurbette id="' . $instance['blurbette_id'] . '" context="widget"]' ); echo '</div>', PHP_EOL; echo $args['after_widget']; endif; } } // end WPCX_Blurbette_Widget