Creating a WordPress Post Meta Widget, Part 2

This is the final installment of our two part series on building a simple WordPress widget that displays the current post’s meta information. You can see part one here.

In this post, we’ll be adding some user-selectable options to our post meta widget. If you’re familiar with the widgets that are included with WordPress, most of them allow you to customize their title as it appears in your blog’s sidebar area. We’ll be adding that option to our widget, as well. In addition, we’re going to add the option to use the current post’s title as our widget title.

WordPress Functions We’ll Be Using

How It Works

Creating an options form for our widget (or a “control” function as the WordPress internals call it) is just as simple — if not simpler — than creating the widget itself. If you have some experience creating and consuming forms in PHP, this really is a snap.

Your options form is really just a standard HTML form that posts back to itself when the user clicks the save button. So, your control function has to do two things:

  1. Save any option values that have been posted to us.
  2. Output the form that allows the user to set option values.

Once we have a control function, we just need to let WordPress know about it using wp_register_widget_control and we’re all set.

The Code

First, a couple notes regarding this particular implementation: To store the option values for our widget, I’m going to use WordPress’ built-in options database. We’ll be adding two options: my_post_meta_widget_title and my_post_meta_widget_use_post_title. Verbose? Yes. Chances of colliding with another option? Pretty slim.

WordPress is even more hands-off with our control function than it is with our widget function. There are no parameters passed to it, and it does not have any constraints regarding its output.

As mentioned previously, the first thing you’ll want your function to do is check the $_POST array to see if we have new values for our options. If there are new values present, we’ll update the values stored in the database. Let’s take a look at what our function will look like with just that code included:

<?php
    function my_post_meta_widget_control(){

        if (isset($_POST['my_post_meta_widget_use_post_title'])) {
            $use_post_title = (int) $_POST['my_post_meta_widget_use_post_title'];
            update_option('my_post_meta_widget_use_post_title', $use_post_title);
        }
        if (isset($_POST['my_post_meta_widget_title'])) {
            $widget_title = esc_attr($_POST['my_post_meta_widget_title']);
            update_option('my_post_meta_widget_title', $widget_title);
        }
    }
?>

Pretty standard PHP so far. Notice, however, that we did use WordPress’ esc_attr function to escape the user-supplied title string, just in case. Notice also that we’re casting my_post_meta_widget_use_post_title to an integer because the form control we’re about to use is a checkbox. That should also take care of any potential strangeness our users might attempt to introduce.

Okay, but what if there were no new values submitted? We need to retrieve the existing values from the database so we can pre-fill the form with our user’s previously selected options or default values if they’ve not made a selection previously. Let’s add that little bit of magic to our function and see what it looks like.

<?php
    function my_post_meta_widget_control(){

        if (isset($_POST['my_post_meta_widget_use_post_title'])) {
            $use_post_title = (int) $_POST['my_post_meta_widget_use_post_title'];
            update_option('my_post_meta_widget_use_post_title', $use_post_title);
        } else {
            $use_post_title = (int) get_option('my_post_meta_widget_use_post_title');
        }
        if (isset($_POST['my_post_meta_widget_title'])) {
            $widget_title = esc_attr($_POST['my_post_meta_widget_title']);
            update_option('my_post_meta_widget_title', $widget_title);
        } else {
            $widget_title = get_option('my_post_meta_widget_title');
        }
        $widget_title = ($widget_title) ? $widget_title : 'About This Post';
    }
?>

Cool. So, if the user gives us new values via $_POST, we write them to the database and use them. Otherwise, we pull the existing values from the database. If we come up empty there, we use a default value for the title. Since the checkbox is just a simple boolean, we don’t bother setting a default.

Side note: If you’re having a little trouble with that last line, I’m using PHP’s ternary operator to assign a default value to the title. More information is available on the ternary operator in the official PHP docs.

Now we’ve got all the info we need to show the user an options form, so let’s do that:

<?php
    function my_post_meta_widget_control(){

        if (isset($_POST['my_post_meta_widget_use_post_title'])) {
            $use_post_title = (int) $_POST['my_post_meta_widget_use_post_title'];
            update_option('my_post_meta_widget_use_post_title', $use_post_title);
        } else {
            $use_post_title = (int) get_option('my_post_meta_widget_use_post_title');
        }
        if (isset($_POST['my_post_meta_widget_title'])) {
            $widget_title = esc_attr($_POST['my_post_meta_widget_title']);
            update_option('my_post_meta_widget_title', $widget_title);
        } else {
            $widget_title = get_option('my_post_meta_widget_title');
        }
        $widget_title = ($widget_title) ? $widget_title : 'About This Post';
        ?>
        <p>
            <input name="my_post_meta_widget_use_post_title" type="hidden" value="0" />
            <input id="my_post_meta_widget_use_post_title" name="my_post_meta_widget_use_post_title" type="checkbox" value="1" <?php if($use_post_title) echo 'checked="checked" '; ?>/>
            <label for="my_post_meta_widget_use_post_title">Use Post Title as Widget Title</label>
        </p>
        <p>
            <label for="my_post_meta_widget_title">Widget Title</label><br />
            <input id="my_post_meta_widget_title" name="my_post_meta_widget_title" type="text" value="<?php echo $widget_title; ?>" />
        </p>
        <?php
    }
?>

We’re using a pretty standard HTML form laced with a little PHP magic to show the user the values they’ve previously selected (or the defaults.)
If you take a close look at our boolean option (the option we used a checkbox to represent) you’ll notice something a little out of the ordinary: a hidden input with the same name as our checkbox and a value of 0 (zero). A checkbox’s value is only included in a form’s post data if the box is checked; otherwise, nothing about the checkbox is sent. Here, we’re taking advantage of another behavior to substitute a 0 value. If the browser encounters two values for the same named form element, it only includes the last one with the post data. So, if the box is checked, the hidden input’s 0 value is ignored, and the checkbox’s 1 is used. However, if the checkbox is unchecked, it is ignored and the 0 is used.

So, we’ve pulled in our new settings if they’re present, and given the user a form to use to change them. All that’s left is to let WordPress know that all this wonderful code exists! For that, we register our function using wp_register_widget_control, like so:

<?php
    function my_post_meta_widget_control(){

        if (isset($_POST['my_post_meta_widget_use_post_title'])) {
            $use_post_title = (int) $_POST['my_post_meta_widget_use_post_title'];
            update_option('my_post_meta_widget_use_post_title', $use_post_title);
        } else {
            $use_post_title = (int) get_option('my_post_meta_widget_use_post_title');
        }
        if (isset($_POST['my_post_meta_widget_title'])) {
            $widget_title = esc_attr($_POST['my_post_meta_widget_title']);
            update_option('my_post_meta_widget_title', $widget_title);
        } else {
            $widget_title = get_option('my_post_meta_widget_title');
        }
        $widget_title = ($widget_title) ? $widget_title : 'About This Post';
        ?>
        <p>
            <input name="my_post_meta_widget_use_post_title" type="hidden" value="0" /> <!-- Rails trick : hidden '0' input stacked behind checkbox -->
            <input id="my_post_meta_widget_use_post_title" name="my_post_meta_widget_use_post_title" type="checkbox" value="1" <?php if($use_post_title) echo 'checked="checked" '; ?>/>
            <label for="my_post_meta_widget_use_post_title">Use Post Title as Widget Title</label>
        </p>
        <p>
            <label for="my_post_meta_widget_title">Widget Title</label><br />
            <input id="my_post_meta_widget_title" name="my_post_meta_widget_title" type="text" value="<?php echo $widget_title; ?>" />
        </p>
        <?php
    }
    wp_register_widget_control('my_post_meta_widget', 'my Current Post Meta', 'my_post_meta_widget_control');
?>

Revisiting Our Widget Code and Adding our Options

In part one, we created a function to display our post-meta widget in our blog’s sidebar. Combine that with the code we just wrote, and you’ll get something like this:

<?php
    function my_post_meta_widget($args) {
        if( ! is_singular() ) return;
        extract($args);
        echo $before_widget . $before_title . 'About This Post' . $after_title;
        ?>
        <ul>
            <li class="date"><?php the_time('F jS, Y'); ?></li>
            <li class="author">By <?php the_author(); ?></li>
            <li class="comments"><?php comments_number(); ?></li>
            <li class="categories">Categories: <?php the_category(', '); ?></li>
            <li class="tags">Tags: <?php the_tags(' ', ', ', ' '); ?></li>
        </ul>
        <?php
        echo $after_widget;
    }
    wp_register_sidebar_widget('my_post_meta_widget_id', 'Post Meta Widget', 'my_post_meta_widget');

    function my_post_meta_widget_control(){

        if (isset($_POST['my_post_meta_widget_use_post_title'])) {
            $use_post_title = (int) $_POST['my_post_meta_widget_use_post_title'];
            update_option('my_post_meta_widget_use_post_title', $use_post_title);
        } else {
            $use_post_title = (int) get_option('my_post_meta_widget_use_post_title');
        }
        if (isset($_POST['my_post_meta_widget_title'])) {
            $widget_title = esc_attr($_POST['my_post_meta_widget_title']);
            update_option('my_post_meta_widget_title', $widget_title);
        } else {
            $widget_title = get_option('my_post_meta_widget_title');
        }
        $widget_title = ($widget_title) ? $widget_title : 'About This Post';
        ?>
        <p>
            <input name="my_post_meta_widget_use_post_title" type="hidden" value="0" />
            <input id="my_post_meta_widget_use_post_title" name="my_post_meta_widget_use_post_title" type="checkbox" value="1" <?php if($use_post_title) echo 'checked="checked" '; ?>/>
            <label for="my_post_meta_widget_use_post_title">Use Post Title as Widget Title</label>
        </p>
        <p>
            <label for="my_post_meta_widget_title">Widget Title</label><br />
            <input id="my_post_meta_widget_title" name="my_post_meta_widget_title" type="text" value="<?php echo $widget_title; ?>" />
        </p>
        <?php
    }
    wp_register_widget_control('my_post_meta_widget_id', 'Post Meta Widget', 'my_post_meta_widget_control');
?>

They look nice together, don’t they? The only trouble is that our control function is doing an awful lot of work for nothing. Right now, the widget function we created is completely ignoring our new options. Let’s drop in a few lines of code that will read our option values from the database and act appropriately:

<?php
    function my_post_meta_widget($args) {
        if( ! is_singular() ) return;
        extract($args);
        echo $before_widget.$before_title;

        $use_post_title = (int) get_option('my_post_meta_widget_use_post_title');
        if($use_post_title) {
            the_title();
        } else {
            $widget_title = get_option('my_post_meta_widget_title');
            $widget_title = ($widget_title) ? $widget_title : 'About This Post';
            echo $widget_title;
        }

        echo $after_title;
        ?>
        <ul>
            <li class="date"><?php the_time('F jS, Y'); ?></li>
            <li class="author">By <?php the_author(); ?></li>
            <li class="comments"><?php comments_number(); ?></li>
            <li class="categories">Categories: <?php the_category(', '); ?></li>
            <li class="tags">Tags: <?php the_tags(' ', ', ', ' '); ?></li>
        </ul>
        <?php
        echo $after_widget;
    }
    wp_register_sidebar_widget('my_post_meta_widget_id', 'Post Meta Widget', 'my_post_meta_widget');

    function my_post_meta_widget_control(){

        if (isset($_POST['my_post_meta_widget_use_post_title'])) {
            $use_post_title = (int) $_POST['my_post_meta_widget_use_post_title'];
            update_option('my_post_meta_widget_use_post_title', $use_post_title);
        } else {
            $use_post_title = (int) get_option('my_post_meta_widget_use_post_title');
        }
        if (isset($_POST['my_post_meta_widget_title'])) {
            $widget_title = esc_attr($_POST['my_post_meta_widget_title']);
            update_option('my_post_meta_widget_title', $widget_title);
        } else {
            $widget_title = get_option('my_post_meta_widget_title');
        }
        $widget_title = ($widget_title) ? $widget_title : 'About This Post';
        ?>
        <p>
            <input name="my_post_meta_widget_use_post_title" type="hidden" value="0" />
            <input id="my_post_meta_widget_use_post_title" name="my_post_meta_widget_use_post_title" type="checkbox" value="1" <?php if($use_post_title) echo 'checked="checked" '; ?>/>
            <label for="my_post_meta_widget_use_post_title">Use Post Title as Widget Title</label>
        </p>
        <p>
            <label for="my_post_meta_widget_title">Widget Title</label><br />
            <input id="my_post_meta_widget_title" name="my_post_meta_widget_title" type="text" value="<?php echo $widget_title; ?>" />
        </p>
        <?php
    }
    wp_register_widget_control('my_post_meta_widget_id', 'Post Meta Widget', 'my_post_meta_widget_control');
?>

Alright, all set. Drop that into your functions.php and let the magic begin!

3 Comments to Creating a WordPress Post Meta Widget, Part 2

  1. by Diego

    on January 5, 2012 at 2:46 pm

    Hi,
    in the last code ‘webpres_post_meta_widget_use_post_title’ is just a typing error or do i miss something? don’t it need ‘my_post_meta_widget_use_post_title’?

  2. by Daniel

    on January 5, 2012 at 4:16 pm

    Oops. That was a typo…I missed that bit when I was copying and pasting the code over from one of our blog themes! I have corrected the code in the post. Thanks!

  3. by Diego

    on January 5, 2012 at 4:28 pm

    thanks to you for the usefull tutorial.

Leave a Reply



 

By submitting a comment here you grant Web Presence Partners a perpetual license to reproduce your words and name/web site in attribution. Inappropriate or irrelevant comments will be removed at an admin's discretion.