How to clean up a bloated function

When you start coding a new feature in WordPress, one of the first thing that comes to mind is the filter to hook into. A few trips down to the Codex and an hour later you’ll have the feature all implemented into a function. You wire it to the filter’s callback and you are done.

This is how you end up with a bloated function. Add up many such functions and pretty soon you’ll end up with a mess on your hands.

Consider the following implementation of a [placeholder] shortcode for the placehold.it service.

function placehold_it_shortcode($attributes) {
  $html = '&lt;img src=&quot;http://placehold.it/';</p>

<p>extract(shortcode_atts(array(
    'width' =&gt; '300',
    'height' =&gt; '200',
    'textcolor' =&gt; null,
    'bgcolor' =&gt; null,
    'text' =&gt; null,
  ), $attributes));</p>

<p>$html .= $width . 'x' . $height;</p>

<p>if ($textcolor &amp;&amp; $bgcolor) {
    $html .= '/' . $bgcolor . '/ ' . $textcolor;
  }</p>

<p>if ($text) {
    $html .= '&amp;text=' . urlencode($text);
  }</p>

<p>$html .= '&quot;&gt;';</p>

<p>return $html;
}

This function transforms the WordPress shortcode [placeholder width='100' height='200'] into an img tag. While it isn’t doing too much right now, when client changes start coming in things could go out of hand.

Now lets try to write this function in a manner that is more manageable. First we’ll break down the roles of the function into it’s parts. Then implement that role using additional helper functions if needed.

  1. Provide defaults Eg:- default width = 300px
  2. Convert shortcode attributes into URL segments
  3. Generate an image tag

1. Provide defaults

Keeping configuration outside helps avoid breaking other code when we change the defaults. So we’ll pull out the defaults into a function.

function get_defaults() {
  return array(
    'width' => '300',
    'height' => '200',
    'textcolor' => null,
    'bgcolor' => null,
    'text' => null
  );
}

2. Convert shortcode attributes into URL segments

Instead of concatenating the segments in one swoop we’ll let individual segments build themselves. Each function will return a string, and we’ll build an array of such segments.

The get_sizes function returns the dimensions of the placeholder.

function get_sizes(&$attrs) {
  return $attrs['width'] . 'x' . $attrs['height'];
}

The get_colors function returns a URL segment as bgcolor/textcolor.

function get_colors(&amp;$attrs) {
  $bgcolor = $attrs['bgcolor'];
  $textcolor = $attrs['textcolor'];</p>

<p>if ($bgcolor &amp;&amp; $textcolor) {
    return $bgcolor . '/' . $textcolor;
  } else {
    return null;
  }
}

The benefit of having segments build themselves becomes apparent now. The get_text function reuses the get_sizes function when the placeholder’s text attribute is not specified.

function get_text(&amp;$attrs) {
  $text = $attrs['text'];
  if (is_null($text)) {
    $text = get_sizes($attrs);
  }</p>

<p>return '&amp;text=' . $text;
}

Next we’ll build the array of URL segments from an array of WordPress shortcode attributes. An add_segment helper comes in handy to skip adding empty segments.

function build_segments(&amp;$attrs) {
  $short_attrs = shortcode_atts(get_defaults(), $attrs);
  $segments = array();</p>

<p>add_segment($segments, get_sizes($short_attrs));
  add_segment($segments, get_colors($short_attrs));
  add_segment($segments, get_text($short_attrs));</p>

<p>return $segments;
}</p>

<p>function add_segment(&amp;$segments, $value) {
  if ($value) {
    array_push($segments, $value);
  }
}

3. Generate an image tag

Finally it’s time to bring this together into the shortcode handler function. We’ve done most of the work for it already, so here we simply grab the segments and return the img tag.

function placehold_it_shortcode($attrs) {
  $segments = build_segments($attrs);
  return '<img src="http://placehold.it/' . implode('/', $segments) . '">';
}

Bloated Function be Gone! And we’ve allowed for greater flexibility when client changes start rolling in!

You can find the full source code of this plugin on GitHub.

In future posts we will explore an Object-Oriented solution to a more involved shortcode API.