In the last part of the series, we looked at registering a custom post type for events. We customized the dashboard by adding a custom metabox and some custom meta fields for inputting event data. To make it easier for the user to input dates, we incorporated the jQuery UI datepicker control in the dashboard, as well.
While WordPress only shows the title and the date column for the custom post type in post admin screen, we added our own custom columns to show event start date, end date and the event venue. Doing so, we completed the most part of our upcoming events plugin.
In the final part of this series, we will:
- look at the WordPress widgets API
- register a widget to show a list of upcoming events
- query the database for upcoming events using the WP_Query class
- make a meta query to compare dates so only the events in the future come up
Let's dive in as we will be going through the process of building a WordPress widget from the ground up.
WordPress Widgets API
We can think of widgets as blocks of code meant to add certain functionality to a site. This could be anything from a calendar, social sharing buttons, a rating system, or a testimonial slider. A user can easily add to or remove them from the site by simply dragging them.
WordPress widgets can be made by extending the WP_Widget
class that WordPress provides. This class contains necessary methods and properties to make a widget work. This includes functions to initialize a widget, show the user interface in the admin, update their different instances, save the new settings in the database and display them on the font-end.
We will extend four functions from the base class to define the functionality of our widget:
__construct()
form()
update()
widget()
Let’s have an overview to each of them:
__construct()
The __construct()
method initializes the widget. It sets up widget name, base id and other information like description and widget class, etc.
form()
This is the function that outputs the settings form in the dashboard. The form may include fields for various options to customize the look and the functionality of the widget on the front-end. The form()
method accepts an argument for the instance of the widget.
update()
This method makes sure that the widget gets updated whenever a new setting is applied to an instance of the widget. It accepts two arguments: one for the old instance and one for new instance of the widget.
widget()
This method outputs the widget content to the front-end of the site. This is where we define what is meant to be seen by the users when they visit the site. This method accepts two arguments:
-
$widget_args
: This is an array containing necessary information about the widget -
$instance
: The instance of the widget to be shown
We will take a closer look at these methods and their arguments in just a while. For now, let’s register our widget class.
Registering the Widget
In the root folder of the plugin, create a new directory named inc
for includes. In that directory, create a file named widget-upcoming-events.php
. We will write all of our widget code in this file to keep things clean and manageable.
We will begin by extending the parent widget class like so:
<?php class Upcoming_Events extends WP_Widget { }
To register the widget, we will use the register_widget()
function in conjunction with the widgets_init
hook:
function uep_register_widget() { register_widget( 'Upcoming_Events' ); } add_action( 'widgets_init', 'uep_register_widget' );
The register_widget()
function accepts the name of the extended class as the argument.
Inside the Upcoming_Events
class, we will define our four methods upon those we had a look in the previous section:
<?php class Upcoming_Events extends WP_Widget { public function __construct() { } public function form( $instance ) { } public function update( $new_instance, $old_instance ) { } public function widget( $args, $instance ) { } }
In the next step, we will write code for each of them and will have a closer look at how they work. But before that, add the following line of code at the end of upcoming-events.php
main plugin file to include the widget:
include( 'inc/widget-upcoming-events.php' );
The __construct()
Method
If you have a background in OOP then you certainly know what constructors are. For beginners, constructors are special functions in a class that are automatically called when an object of that class is instantiated.
Since we have a class for a widget, we need to have a function that sets up certain things like the id and the widget name whenever that widget is instantiated and that’s where the __construct()
method comes into play.
The __construct()
method of the parent class accepts three arguments:
-
$base_id
: The unique id for the widget -
$title
: The title of the widget in the admin area. Should be marked for translation -
$widget_ops
: An array containing other widget options like widget class and widget description etc
Now that we know what __construct()
does and what arguments it accepts, let’s write code for it:
public function __construct() { $widget_ops = array( 'class' => 'uep_upcoming_events', 'description' => __( 'A widget to display a list of upcoming events', 'uep' ) ); parent::__construct( 'uep_upcoming_events', //base id __( 'Upcoming Events', 'uep' ), //title $widget_ops ); }
In the __construct()
method of our widget, we made a call to the __construct()
method of the parent class denoted by parent::__construct()
and passed three arguments for base id, title and widget options. Also note that the strings are marked for translation using the __()
function.
The form()
Method
The form()
method is where we define the body of our widget that will show in the WordPress admin. It accepts one argument $instance
for the instance of the widget.
We need to provide user a text field to input the widget title. Also, he or she should be able to choose between the number of events he want to show on the site. But these fields should also have some default values in case the user doesn’t want to input his own.
First, we will define the default values for our fields:
$widget_defaults = array( 'title' => 'Upcoming Events', 'number_events' => 5 ); $instance = wp_parse_args( (array) $instance, $widget_defaults );
We defined our defaults in an array with keys as field names. We then used the wp_parse_args()
utility function that merges an array of arguments (in our case - $instance
) with an array of default values (in this case - $widget_defaults
). Also note that we have typecast the $instance
as an array.
It’s time to render form fields for the title and the number of events. Let’s begin by creating a text field for the title:
<p> <label for="<?php echo $this->get_field_id( 'title' ); ?>"><?php _e( 'Title', 'uep' ); ?></label> <input type="text" id="<?php echo $this->get_field_id( 'title' ); ?>" name="<?php echo $this->get_field_name( 'title' ); ?>" class="widefat" value="<?php echo esc_attr( $instance['title'] ); ?>"> </p>
First of all, we created a paragraph as a container element (although you could just as easily as used a div
). Then we created a label for the input field. We don’t need to give it an id manually as WordPress will take care of it by itself. It provides us with some utility functions for better working with field names and ids. It will generate a unique id and name for every field in the form each time we create an instance of the widget, thus enabling us to create as many as instances of the same widget.
The method used to generate the field id is get_field_id()
preceded by a $this->
, which is a way of telling that this method belongs to the same class. This method is already defined in the base WP_Widget
class and since we extended it with our own class, it becomes readily available. The method accepts an argument for the field we are generating an id for.
We marked the label text for translation by using the _e()
function.
The next method we used is get_field_name()
which works in the same way as get_field_id()
except that it generates a value for the name attribute of the field.
The class widefat
we have given to the input field is a default WordPress class that styles the input fields in the WordPress admin.
Then for the value attribute of the input field, we simply echoed the contents of $instance['title']
while passing it through the esc_attr()
function to encode any unwanted characters.
For the select dropdown to specify the number of events to show, add the following code in the form()
method:
<p> <label for="<?php echo $this->get_field_id( 'number_events' ); ?>"><?php _e( 'Number of events to show', 'uep' ); ?></label> <select id="<?php echo $this->get_field_id( 'number_events' ); ?>" name="<?php echo $this->get_field_name( 'number_events' ); ?>" class="widefat"> <?php for ( $i = 1; $i <= 10; $i++ ): ?> <option value="<?php echo $i; ?>" <?php selected( $i, $instance['number_events'], true ); ?>><?php echo $i; ?></option> <?php endfor; ?> </select> </p>
The code is pretty much the same as the code for the title field except that we ran a loop for creating the option tags. To check whether an option is currently selected, we used another WordPress utility function selected()
that compares two given values (in this case - $i
and $instance['number_events']
) and then adds the selected
attribute to the current option tag if the values are equal.
That’s all about the form()
method. We now need to make sure that our widget gets updated whenever a new change is applied to it.
The update()
Method
The update()
method makes it so that we are able to update the values that a widget manages. It accepts two arguments $old_instance
and $new_instance
and returns the updated instance of the widget.
The code is quite simple:
public function update( $new_instance, $old_instance ) { $instance = $old_instance; $instance['title'] = $new_instance['title']; $instance['number_events'] = $new_instance['number_events']; return $instance; }
So every time a change has been made to an instance of the widget by the user, the update()
method will update the settings in the database thus keeping the widget updated with new settings.
The widget()
Method
This is the most important method of all as it displays intended content on the front-end of the site. It accepts two arguments $args
and $instance
. The $args
array contains the following elements:
-
$name
: The name of the sidebar in which the widget is being displayed -
$id
: The id of the respected sidebar -
$description
: The description of the sidebar -
$class
: The sidebar class -
$before_widget
: The HTML that would come before the widget. Could be an opening tag of the containing element -
$after_widget
: The HTML that would come after the widget. Generally a closing tag of the containing element -
$before_title
: The HTML that will be placed before the title of the widget -
$after_title
: The HTML preceded by the title of the widget -
$widget_id
: The id of that particular instance of the widget. This is NOT the base id of the widget -
$widget_name
: The name of widget as passed when registering the widget
If you have ever registered a sidebar for a WordPress theme then the first eight elements of the $args
array should look familiar to you. The last two elements are widget specific.
Let’s extract the $args
array and apply the widget_title
filter to the widget title:
public function widget( $args, $instance ) { extract( $args ); $title = apply_filters( 'widget_title', $instance['title'] ); }
Now it’s time to prepare the query for retrieving a list of events. We will use the WP_Query
class for this purpose along with the meta query:
$query_args = array( 'post_type' => 'event', 'posts_per_page' => $instance['number_events'], 'post_status' => 'publish', 'ignore_sticky_posts' => true, 'meta_key' => 'event-start-date', 'orderby' => 'meta_value_num', 'order' => 'ASC' ); $upcoming_events = new WP_Query( $query_args );
Since we want to sort our events in the ascending order by their start dates, we have set the meta_key
to the event-start-date
meta value of our events. Along with that, we have told WordPress that we are comparing numbers here (not the strings) by setting the orderby
to meta_value_num
. If you set orderby
to just meta_value
, the WordPress will make the comparison as if it’s comparing strings and that’s not what we want.
The above query will retrieve the given number of events in ascending order with respect to their start dates. But we also want to screen out events that have already past i.e. their event-end-date
meta value is less than the current time stamp. For that to be accomplished, we will pass a meta query that will check for their end dates:
$meta_quer_args = array( 'relation' => 'AND', array( 'key' => 'event-end-date', 'value' => time(), 'compare' => '>=' ) ); $query_args = array( 'post_type' => 'event', 'posts_per_page' => $instance['number_events'], 'post_status' => 'publish', 'ignore_sticky_posts' => true, 'meta_key' => 'event-start-date', 'orderby' => 'meta_value_num', 'order' => 'ASC', 'meta_query' => $meta_quer_args ); $upcoming_events = new WP_Query( $query_args );
In the above code, we compared the event-end-date
meta value to be greater than or equal to the current time stamp. Now, only the events with their event-end-date
meta values greater than the current time stamp, i.e. the events upcoming in the future will be retrieved.
Now that we have retrieved the events, let’s begin spitting out the content of our widget:
echo $before_widget; if ( $title ) { echo $before_title . $title . $after_title; } ?> <ul class="uep_event_entries"> <?php while( $upcoming_events->have_posts() ): $upcoming_events->the_post(); $event_start_date = get_post_meta( get_the_ID(), 'event-start-date', true ); $event_end_date = get_post_meta( get_the_ID(), 'event-end-date', true ); $event_venue = get_post_meta( get_the_ID(), 'event-venue', true ); ?> <li class="uep_event_entry"> <h4><a href="<?php the_permalink(); ?>" class="uep_event_title"><?php the_title(); ?></a> <span class="event_venue">at <?php echo $event_venue; ?></span></h4> <?php the_excerpt(); ?> <time class="uep_event_date"><?php echo date( 'F d, Y', $event_start_date ); ?> – <?php echo date( 'F d, Y', $event_end_date ); ?></time> </li> <?php endwhile; ?> </ul> <a href="<?php echo get_post_type_archive_link( 'event' ); ?>">View All Events</a> <?php wp_reset_query(); echo $after_widget;
The above code should be self-explanatory: We first echoed the content of $before_widget
as an opening tag of the containing element. Then we checked if the widget has a title, if so, we printed it out while wrapping it between $before_title
and $after_title
.
After that, we looped through the events that we had retrieved – printing out their titles, excerpts and other information like dates and venues. At the end, we added a link to their archive page using the function get_post_type_archive_link()
that returns a permalink to the archive page of the given post type. We then wrapped up our widget by echoing the $after_widget
closing tag.
Let's write some basic styles for our widget in the css/style.css
file:
.uep_event_entry{ margin-bottom: 21px; } .uep_event_entry h4{ margin-bottom: 3px; } .uep_event_entry h4 a{ text-decoration: none; color: inherit; } .uep_event_entry .event_venue{ font-size: 0.9em; color: #777777; font-weight: normal; font-style: italic; } .uep_event_entry p{ margin-bottom: 3px !important; } .uep_event_entry .uep_event_date{ font-size: 0.9em; color: #777777; }
Now we need to include this file on the front-end but only when our widget is currently activated. We will check if our widget is currently being displayed on the front-end by using the is_active_widget()
function which accepts four arguments and all of them are optional:
-
$callback
: The widget callback to check -
$widget_id
: Widget id. Needed for checking -
$id_base
: The base id of the widget as passed in the__construct()
method -
$skip_inactive
: Whether to skip the inactive widgets
Add the following code below the uep_admin_script_style()
function in the upcoming-events.php
main plugin file:
function uep_widget_style() { if ( is_active_widget( '', '', 'uep_upcoming_events', true ) ) { wp_enqueue_style( 'upcoming-events', STYLES . 'upcoming-events.css', false, '1.0', 'all' ); } } add_action( 'wp_enqueue_scripts', 'uep_widget_style' );
Hence we first checked if the widget is currently active. If so, we enqueued the stylesheet using the wp_enqueue_style()
function.
That’s all about the widget()
method. We have successfully created a widget that shows a list of upcoming events along with the other associated information.
Flushing Rewrite Rules
We have almost completed our plugin and the widget but we still have a little problem – click on any of the event title and you might get a "page not found error." That’s because whenever we register a post type via plugin, we need to flush rewrite rules upon plugin activation for proper working of permalink structure.
You might get your links working by changing the permalink structure but that’s not the ideal way; therefore, we will flush rewrite rules every time our plugin has been activated.
Add the following code inside your upcoming-events.php
file:
function uep_activation_callback() { uep_custom_post_type(); flush_rewrite_rules(); } register_activation_hook( __FILE__, 'uep_activation_callback' );
So we registered the activation hook for our plugin using the register_activation_hook()
function that accepts two arguments:
-
$file
: The path to the main plugin file -
$function
: The callback function to be run whenever the plugin is activated
In the callback function of our hook, we first added the custom post type of events into the database using the function uep_custom_post_type()
we had defined earlier in our previous tutorial.
We then flushed rewrite rules using the flush_rewrite_rules()
function. Now you might want to deactivate the plugin and activate it back to ensure that rewrite rules have been flushed, doing so, your links should now work fine and redirect you to the event’s single page.
Conclusion
This has been quite another lengthy tutorial in which we wrote a lot of code and looked at various WordPress functions. We created a WordPress widget from scratch by extending the parent WP_Widget
class and looked at the member functions that this class provides to define the functionality of our widget. We also wrote a query leveraging the power of WP_Query
class to retrieve a list of events filtered by their meta values.
With this, we also conclude our three part series. I hope that this series will help new readers out there who are just starting out with WordPress and also those looking to enhance their knowledge of WordPress plugin and widget development.
You can access the complete code of the plugin on my GitHub page and below are some links for further exploration of the topics covered in this tutorial:
-
WordPress Widgets API
- Class Reference: WP_Query
- Mastering WordPress Meta Data: An Introduction To Meta Data
-
Object-Oriented Programming in WordPress: An Introduction
Comments