?

Log in

No account? Create an account
entries friends calendar profile Elf Sternberg's Pendorwright Projects Previous Previous Next Next
A Wordpress Plug-In: Illustrated Recent Posts - Elf M. Sternberg
elfs
elfs
A Wordpress Plug-In: Illustrated Recent Posts

I’ll hang my head in shame later. So, I wrote this for my wife, it’s a hack on the “recent_posts” function from default-widgets.php, which comes with WordPress. It’s magic is that it scans each post for an IMG tag and, if it finds one, inserts that as the background of the list object. A little CSS magic drops the opacity down of the image down a dark grey, so it makes a nicely textured list. Since she’s a podcaster who comments on video games, I also provided the capacity to pick a category (“podcasts”) and show only those in the list. She includes screenshots with her podcast announcements, and the combination turns out to be quite lovely. We’ll be rolling out the final website later this month, so you’ll have to take my word for it.


But, to make it fun, I decided to hack the recent posts scripts to use as much functional programming as possible. I couldn’t do it with WordPress’s theLoop(), because that doesn’t convert nicely into an iterator, but I could down in the category form, which does have an array of categories.


The first part was to get the list of categories, and to pull out the base for each input field:


    $cats_instance = $instance['cats'];
    $option_base ='<input type="checkbox" id="'. $this->get_field_id('cats') .'[]" name="'. $this->get_field_name('cats') .'[]"';

The second part takes any given category we want to show and know if it’s checked. This is a pure function; we want to transform a category into a boolean which asserts that it’s in the list of categories picked for this instance. We need to pass the instance into the main function, and PHP provides the use keyword to enclose variable in an anonymous function. Then, when this function is called, we need to enclose the passed-in variable to our is_a_cat function so we can scan it against cats_instance (which, now that I think about it, should really be named instance_cats, but whatever):


    $isChecked = function($c) use ($cats_instance) {
      $is_a_cat = function($ic) use ($c) { return ($ic == $c->term_id); };
      return (count(array_filter($cats_instance, $is_a_cat)) > 0);
    };

And finally, we’re going to reduce the list of all categories to an HTML string representing the form. We need to pass in $isChecked and $option_base.  Because of a bug in array_reduce, the container type declaration only ever takes a NULL or an integer, never a string or array, so the if statement there works around that.  Sadly, it’s a work-around, not a proper guard condition.


    $reduce_categories = function($result, $c) use ($isChecked, $option_base) {
      $checked = ($isChecked($c)) ? ' checked="checked"' : '';
      if ($result == NULL) {
        return $option_base . $checked . ' value="' . $c->term_id.'" /> ' . $c->cat_name . '<br />';
      }
      return $result . $option_base . $checked . ' value="' . $c->term_id.'" /&t; ' . $c->cat_name . '<br />';
    };

This is echoed immediately afterward to the screen.  Note the almost complete lack of variables.  Even $reduce_categories() is effectively invariant for this call.


<?php echo array_reduce(get_categories('hide_empty=0'), $reduce_categories, NULL); ?>

In all, this is a nicely functional routine in which we describe how the result is built, isolate exactly those elements necessary to build the result, and describe with some precision the enclosures necessary for each function to make sense.


I don’t know PHP at all.  PHP5 looks like some unholy archaic Perl crossover with some weird modern additions tacked on.  There’s still too many variables and references in this code and whether or not PHP is pass-by-reference or pass-by-value, or the oddly intuitive hybrid that lives in Java, Python and Javascript, still escapes me.  There’s no equivalent of the in_array() function that takes a callback as its truth function, so isChecked() scans the entire array on every iteration.


But this was fun. And it works on PHP 5.3 and above. And I can claim, with some truthiness, that it’s both functional and less error-prone. And that makes me happy.

Leave a comment