Theme-ready Widgets in WordPress

If you use WordPress, you’ve probably used a handful of widgets in your sidebar.

Some display statistics.  Others print out recent comments.  Others display posts related to the content in the main window.

But all of them do this in the exact same way.  They take some data, wrap it into a hard-coded HTML template, and dump the content of that template to the front page of your site.

For most sites, this is fine.  Each tag has enough information to be easily styled, moved, re-sized, or even re-positioned using CSS.  In some cases, it’s not enough.

I’m a bit of a control freak, and I like to know exactly what is being output on my site, why, and how to change it.  As a result, I build my custom widgets to use customizable templates.

I set the default look – you can change it to whatever you want.

Core Contributions Widget

Core contributions widgets in the sidebar of my personal site.

The first system I built that implemented this model is the WP Core Contributions Widget.  In reality, it’s two widgets that you can place in your sidebar. One lists your code contributions via Trac. The other lists your documentation contributions via the Codex.

The plugin includes two template files that define the default structure for the widgets.  But the plugin code lets you override this with your theme.

The first widget displays a list of your contributions to WordPress core development, parsed from the search results of “props {username}” for your Trac username.

The structure itself is fairly basic:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<?php if ( isset( $items ) ) : ?>
  <ul>
  <?php foreach ( (array) $items as $item ) : ?>
    <li>
      <?php printf( __( '[%1$s] for %2$s' ),
        '<a href="' . $item['link'] . '">'
          . $item['changeset'] . '</a>',
        '<a href="' . 'http://core.trac.wordpress.org/ticket/'
          . $item['ticket'] . '">' . '#' . $item['ticket']
          . '</a>'
        ); ?>
      </li>
  <?php endforeach; ?>
  </ul>
  <p>
    <a href="<?php echo esc_url( 'https://core.trac.wordpress.org/search?q='
      . $user . '&noquickjump=1&changeset=on&max=20' ); ?>">
      <?php _e( "View all tickets on Trac." ); ?>
    </a>
  </p>
<?php endif; ?>

But it all hinges on the contents of the $items variable.  This variable structure is defined in the plugin readme, and it actually contains more information that I use in my template:

  • link -> A link to the actual Trac changeset.
  • changeset -> The ID of the changeset.
  • description -> The commit message for the changeset.
  • ticket -> The ID of the ticket fixed by the patch.

I’m not even using the description element, but it’s available should you wish to use it in your own template.

Defining the Widget

If you’re using WordPress’ modern widgets API, you create a new widget by extending the default WP_Widget class.  You define the options form, the widget’s update behavior, and the output of the widget itself.

In the case of a themeable widget, you skip this last step.  Instead, you create an object or array containing the data that the widget will render, then pass it on to whatever template does the rendering.

A themeable widget will attempt to find a widget template in the theme – if there isn’t one, it will load a default template instead:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
function widget( $args, $instance ){
  extract( $args );
  $title = apply_filters( 'widget_title', $instance['title'] );
  $user = $instance['trac-user'];
  $count = isset($instance['display-count'])
    ? $instance['display-count'] : 10;

  echo $before_widget;

  if ( $title ) {
    echo $before_title . $title . $after_title;
  }

  // Widget content
  $items = array_slice( WPCC::get_items($user), 0, $count );
  $total = WPCC::get_changeset_count($user);

  // Include template - can be overriden by a theme!
  $template_name = 'wp-core-contributions-widget-template.php';
  $path = locate_template( $template_name );
  if ( empty( $path ) ) {
    $path = WPCC . 'inc/' . $template_name;
  }

  // This include will generate the markup for the widget
  include( $path );

  echo $after_widget;
}

If your theme contains a wp-core-contributions-widget-template.php file, the widget will load it and let it do the heavy lifting.  If not, it loads the default template I ship with the plugin instead.

Not Just Widgets

There is no reason to limit this kind of templating system to widgets.

I am actually in the process of rewriting WP Publication Archive to implement this same functionality for WordPress shortcodes.  By default, the shortcode will generate content with one specific structure, but you can override this in a theme and customize the output however you want.

The only limit, really, is your imagination.

About Eric

Eric Mann is a writer, web developer, and outdoorsman living in the Pacific Northwest. If he's not working with new technologies in web development, you can probably find him out running, climbing, or hiking with his dog.

Leave a Reply