WordPress: Create a Custom Widget (Part 2)

| 4 comments

This entry is part of my WordPress development series, providing tutorials on specific things you can do in WordPress. Read some more?

In the second part of this tutorial, we are going to expand upon our basic custom widget we have already created by utilizing a simple form in the back-end. Unlike in the previous tutorial where each instance of the widget on our website displays the same, uneditable information, this widget will be able to have unique information for each instance of the widget placed throughout our website.

Create Our Widget

We begin much like we did in part 1 of this tutorial, by creating our own class that extends the WP_Widget class in our functions.php file. This time I have called it My_Adv_Cat_Widget.

<?php
class My_Adv_Cat_Widget extends WP_Widget {

	// Create widget
	public function __construct() {
		parent::__construct(
	 		'my_adv_cat_widget', // Base ID
			'My Advanced Cat Widget', // Name
			array( 'description' => 'This is my advanced cat widget.') // Arguments
		);
	}
}
?>

We again give our widget a base ID, name, and description. Following this first section inside of our class, we add the code below for displaying our widget on the front-end of our website. We have more code inside the widget() function this time because we will be gathering and displaying more information using the form we will create for the back-end.

The Front-End Display

<?php
// Front-End Display of the Widget
public function widget( $instance ) {
	// Saved widget options
	$title = apply_filters( 'widget_title', $instance['title'] );
	$catName = $instance['cat_name'];
	$catAge  = $instance['cat_age'];
	$favToy  = $instance['fav_toy'];
	$desc    = apply_filters( 'widget_textarea', empty( $instance['description'] ) ? '' : $instance['description'], $instance );

	// Display information
	echo '<div class="my-widget block">';
		if ( !empty( $title ) ) {
			echo '<h3>' . $title . '</h3>';
		}
		if ( !empty( $catName ) ) {
			echo '<p><strong>Name:</strong> ' . $catName . '<br />';
		}
		if ( !empty( $catAge ) ) {
			echo '<strong>Age:</strong> ' . $catAge . '<br />';
		}
		if ( !empty( $favToy ) ) {
			echo '<strong>Favourite Toy:</strong> ' . $favToy . '</p>';
		}
		if ( !empty( $desc ) ) {
			echo wpautop( $desc );
		}
	echo '</div>';
}
?>

First we get the values of the saved form options, and store in variables. Below that, we display the values if they exist. For our description, since it is going to be a textarea, we are using the widget_textarea filter and the wpautop() function to save and display paragraphs from the textarea.

The Back-End Form

<?php
// Back-end form of the Widget
public function form( $instance ) {
	// Check for values
	if ( isset( $instance[ 'title' ] ) ) {
		$title = $instance[ 'title' ];
	}
	if ( isset( $instance[ 'cat_name' ] ) ) {
		$catName = $instance[ 'cat_name' ];
	}
	if ( isset( $instance[ 'cat_age' ] ) ) {
		$catAge = $instance[ 'cat_age' ];
	}
	if ( isset( $instance[ 'fav_toy' ] ) ) {
		$favToy = $instance[ 'fav_toy' ];
	}
	if ( isset( $instance[ 'description' ] ) ) {
		$desc = $instance[ 'description' ];
	}
	?>
	<p>
		<label for="<?php echo $this->get_field_id( 'title' ); ?>">Title:</label> 
		<input class="widefat" id="<?php echo $this->get_field_id( 'title' ); ?>" name="<?php echo $this->get_field_name( 'title' ); ?>" type="text" value="<?php echo esc_attr( $title ); ?>">
	</p>
	<p>
		<label for="<?php echo $this->get_field_id( 'cat_name' ); ?>">Name:</label> 
		<input class="widefat" id="<?php echo $this->get_field_id( 'cat_name' ); ?>" name="<?php echo $this->get_field_name( 'cat_name' ); ?>" type="text" value="<?php echo esc_attr( $catName ); ?>">
	</p>
	<p>
		<label for="<?php echo $this->get_field_id( 'cat_age' ); ?>">Age:</label> 
		<select class="widefat" id="<?php echo $this->get_field_id('cat_age'); ?>" name="<?php echo $this->get_field_name('cat_age'); ?>">
			<?php
				$options = array( '1', '2', '3', '4', '5', '6', '7', '8', '9', '10', '11', '12', '13', '14', '15', '16', '17', '18', '19', '20' );
				foreach ( $options as $option ) {
					echo '<option value="' . $option . '" id="' . $option . '"', $catAge == $option ? ' selected="selected"' : '', '>' . $option . '</option>';
				}
			?>
		</select>
	</p>
	<p>
		<label for="<?php echo $this->get_field_id( 'fav_toy' ); ?>">Favourite Toy:</label> 
		<input class="widefat" id="<?php echo $this->get_field_id( 'fav_toy' ); ?>" name="<?php echo $this->get_field_name( 'fav_toy' ); ?>" type="text" value="<?php echo esc_attr( $favToy ); ?>">
	</p>
	<p>
		<label for="<?php echo $this->get_field_id( 'description' ); ?>">Description:</label> 
		<textarea class="widefat" id="<?php echo $this->get_field_id('description'); ?>" name="<?php echo $this->get_field_name('description'); ?>" rows="16" cols="20"><?php echo $desc; ?></textarea>
	</p>
<?php 
}
?>

Next we add in the section for our admin back-end, the form() function. Here we are using a few different form elements – inputs, a select, and a textarea.

First we begin by checking for the values of each of our form’s elements. If they have been set, we store these values in variables, which we then use to pre-populate the form elements. This is so when you go back to edit the widget at a later time, you will see the values in the form that were previously saved.

Below that is where we have the code for our form elements. We utilize the class widefat from WordPress for consistent styling. get_field_id() and get_field_name() are used to get the ID and Name for each form element in this instance of the widget. Other elements can be added to widget forms, such as radio buttons and checkboxes.

In this last piece of our class, the update() function, we sanitize and return the safe values of the form to be saved.

<?php
// Sanitize and return the safe form values
public function update( $new_instance, $old_instance ) {
	$instance = array();
	$instance['title']       = ( !empty( $new_instance['title'] ) ) ? strip_tags( $new_instance['title'] ) : '';
	$instance['cat_name']    = ( !empty( $new_instance['cat_name'] ) ) ? strip_tags( $new_instance['cat_name'] ) : '';
	$instance['cat_age']     = ( !empty( $new_instance['cat_age'] ) ) ? strip_tags( $new_instance['cat_age'] ) : '';
	$instance['fav_toy']     = ( !empty( $new_instance['fav_toy'] ) ) ? strip_tags( $new_instance['fav_toy'] ) : '';
	if ( current_user_can('unfiltered_html') ) {
		$instance['description'] =  $new_instance['description'];
	} else {
		$instance['description'] = stripslashes( wp_filter_post_kses( addslashes($new_instance['description']) ) );
	}

	return $instance;
}
?>

Register Our Widget

As we did in part 1, we must register our widget.

<?php
// Register widget
add_action( 'widgets_init', function(){
     register_widget( 'My_Adv_Cat_Widget' );
});
?>

The Final Code

This is what my final code looks like:

<?php
class My_Adv_Cat_Widget extends WP_Widget {

	// Create widget
	public function __construct() {
		parent::__construct(
	 		'my_adv_cat_widget', // Base ID
			'My Advanced Cat Widget', // Name
			array( 'description' => 'This is my advanced cat widget.') // Arguments
		);
	}

	// Front-End Display of the Widget
	public function widget( $args, $instance ) {
		// Saved widget options
		$title   = $instance['title'];
		$catName = $instance['cat_name'];
		$catAge  = $instance['cat_age'];
		$favToy  = $instance['fav_toy'];
		$desc    = apply_filters( 'widget_textarea', empty( $instance['description'] ) ? '' : $instance['description'], $instance );

		// Display information
		echo '<div class="my-widget block">';
			if ( !empty( $title ) ) {
				echo '<h3>' . $title . '</h3>';
			}
			if ( !empty( $catName ) ) {
				echo '<p><strong>Name:</strong> ' . $catName . '<br />';
			}
			if ( !empty( $catAge ) ) {
				echo '<strong>Age:</strong> ' . $catAge . '<br />';
			}
			if ( !empty( $favToy ) ) {
				echo '<strong>Favourite Toy:</strong> ' . $favToy . '</p>';
			}
			if ( !empty( $desc ) ) {
				echo wpautop( $desc );
			}
		echo '</div>';
	}

	// Back-end form of the Widget
	public function form( $instance ) {
		// Check for values
		if ( isset( $instance[ 'title' ] ) ) {
			$title = $instance[ 'title' ];
		}
		if ( isset( $instance[ 'cat_name' ] ) ) {
			$catName = $instance[ 'cat_name' ];
		}
		if ( isset( $instance[ 'cat_age' ] ) ) {
			$catAge = $instance[ 'cat_age' ];
		}
		if ( isset( $instance[ 'fav_toy' ] ) ) {
			$favToy = $instance[ 'fav_toy' ];
		}
		if ( isset( $instance[ 'description' ] ) ) {
			$desc = $instance[ 'description' ];
		}
		?>
		<p>
			<label for="<?php echo $this->get_field_id( 'title' ); ?>">Title:</label> 
			<input class="widefat" id="<?php echo $this->get_field_id( 'title' ); ?>" name="<?php echo $this->get_field_name( 'title' ); ?>" type="text" value="<?php echo esc_attr( $title ); ?>">
		</p>
		<p>
			<label for="<?php echo $this->get_field_id( 'cat_name' ); ?>">Name:</label> 
			<input class="widefat" id="<?php echo $this->get_field_id( 'cat_name' ); ?>" name="<?php echo $this->get_field_name( 'cat_name' ); ?>" type="text" value="<?php echo esc_attr( $catName ); ?>">
		</p>
		<p>
			<label for="<?php echo $this->get_field_id( 'cat_age' ); ?>">Age:</label> 
			<select class="widefat" id="<?php echo $this->get_field_id('cat_age'); ?>" name="<?php echo $this->get_field_name('cat_age'); ?>">
				<?php
					$options = array( '1', '2', '3', '4', '5', '6', '7', '8', '9', '10', '11', '12', '13', '14', '15', '16', '17', '18', '19', '20' );
					foreach ( $options as $option ) {
						echo '<option value="' . $option . '" id="' . $option . '"', $catAge == $option ? ' selected="selected"' : '', '>' . $option . '</option>';
					}
				?>
			</select>
		</p>
		<p>
			<label for="<?php echo $this->get_field_id( 'fav_toy' ); ?>">Favourite Toy:</label> 
			<input class="widefat" id="<?php echo $this->get_field_id( 'fav_toy' ); ?>" name="<?php echo $this->get_field_name( 'fav_toy' ); ?>" type="text" value="<?php echo esc_attr( $favToy ); ?>">
		</p>
		<p>
			<label for="<?php echo $this->get_field_id( 'description' ); ?>">Description:</label> 
			<textarea class="widefat" id="<?php echo $this->get_field_id('description'); ?>" name="<?php echo $this->get_field_name('description'); ?>" rows="16" cols="20"><?php echo $desc; ?></textarea>
		</p>
	<?php 
	}

	// Sanitize and return the safe form values
	public function update( $new_instance, $old_instance ) {
		$instance = array();
		$instance['title']       = ( !empty( $new_instance['title'] ) ) ? strip_tags( $new_instance['title'] ) : '';
		$instance['cat_name']    = ( !empty( $new_instance['cat_name'] ) ) ? strip_tags( $new_instance['cat_name'] ) : '';
		$instance['cat_age']     = ( !empty( $new_instance['cat_age'] ) ) ? strip_tags( $new_instance['cat_age'] ) : '';
		$instance['fav_toy']     = ( !empty( $new_instance['fav_toy'] ) ) ? strip_tags( $new_instance['fav_toy'] ) : '';
		if ( current_user_can('unfiltered_html') ) {
			$instance['description'] =  $new_instance['description'];
		} else {
			$instance['description'] = stripslashes( wp_filter_post_kses( addslashes($new_instance['description']) ) );
		}

		return $instance;
	}
}

// Register widget
add_action( 'widgets_init', function(){
     register_widget( 'My_Adv_Cat_Widget' );
});
?>

In the back-end, this is what my widget looks like in the list of available widgets to choose from:

My Advanced Cat Widget in the WP admin

After I have placed it in a widgetized area and filled it out, here is what the form looks like:

My Advanced Cat Widget form in the WP admin

What kinds of widgets will you make? Leave your comments down below!