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:

  1. __construct(): the constructor which simply defines some strings and calls the parent method,
  2. form(): presents the draggable widget form in the admin panel,
  3. update(): operates when the form is updated,
  4. 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