How to REALLY check if the content is empty in WordPress

Problem: You want to check if the content in a WordPress post is empty. Seems easy, but do a Google search on the topic and you’ll see the question asked and — incorrectly — answered several times.

The fact is, I know how to do this. I was just hoping there was a built-in function in WordPress that I didn’t know about. Apparently not, so I wrote my own.

Why isn’t it easy and obvious how to check for the content being empty? Well, you could do this:

if ($post->post_content == '') { ... }

That will work. If the content is really empty. That means a zero-length string. As in strlen($post->post_content) == 0. Which it might be. But probably not.

If you’ve worked with real world site content, or even someone else’s Word documents before, you know that blank space is invisible, and a lot of times there’s a lot of blank space in a document that is not truly “empty.” Spaces, line breaks, HTML paragraphs with nothing but a non-breaking space in them. It all takes up space, and makes the content look empty, even when it’s not.

That last example is the critical one here. A WordPress post may look like it has no content, but if someone pressed Enter while the cursor was in the content box and then saved the page, it most likely has at least one <p>&nbsp;</p> in it.

So what you need is a function that takes all of that invisible cruft into account. Since it doesn’t seem like WordPress has such a function built in, I wrote my own, which I have made as compact as possible:

function empty_content($str) {
    return trim(str_replace('&nbsp;','',strip_tags($str))) == '';
}

This function takes the string you pass into it, strips out all HTML tags, then removes any non-breaking space entities, and then trims all whitespace. If there’s nothing but that stuff, then it becomes an empty string. If there’s any “real” content, the string won’t be empty. Then it just compares whatever it has left against an actual empty string, and returns the boolean result.

So now if you want to check if the WordPress content is really empty, you can do this:

if (empty_content($post->post_content)) { ... }

This will return true if the content is empty; false if it’s not.

Update (8/31/2017): This post continues to be one of the most frequently viewed on my blog, and I’ve been meaning for ages to amend it with this important note. As written here, you’ll get an erroneous true returned if the only content is in HTML, for instance, an image. If you want the function to return false if there’s no text content, then leave it as-is. But you can add a second input parameter to the strip_tags() function to tell it to leave certain HTML tags alone. If you want to allow image tags, for instance, the modified code would read as such:

function empty_content($str) {
    return trim(str_replace('&nbsp;','',strip_tags($str,'<img>'))) == '';
}

How to really exclude the home page in the WordPress wp_page_menu() function

I’m posting this little tip for my future self as much as for anyone else.

The problem: It seems that in recent years WordPress has all-but-deprecated the wp_page_menu() function in favor of the wp_nav_menu() function, but the latter is primarily intended for Custom Menus, and there are some cases where Custom Menus aren’t what you want.

I’m working on a couple of sites right now that have a lot of pages, and I don’t want their editors to have to go over to Appearance > Menus every time they add or move a page. I’m relying on the CMS Tree Page View plugin on these sites to allow the clients to leverage the built in Parent / Order settings on pages to manage their primary navigation, rather than managing a separate Custom Menu.

Since I’m not using a Custom Menu, I don’t want to use wp_nav_menu() at all; I pretty much have to use wp_page_menu(). Which is fine. Except for the fact that the site designs do not call for having Home in the navigation.

No problem, right? After all, I can just add 'show_home' => false to the arguments passed to the function, and it will remove the home page.

But it doesn’t.

I’m not entirely sure what’s going on in the WordPress core here, but I suspect that show_home only works if you’re using the old school default configuration of WordPress that calls for the home page being the main “posts” page. And who does that anymore? If you’ve created a custom home page, even if you’ve configured WordPress properly to display it as the main page, this function doesn’t care. (Do functions “care” about anything? But I digress…)

Remember also that there’s an exclude argument, to which you can pass a comma-delimited string of post IDs to exclude. That works, but… ugh. You mean I really have to hardcode the post ID of the home page right into my header.php file?

Of course not. Use this: get_option('page_on_front') and it will automatically find the home page. This is great if you want to be able to reuse a theme or custom function on multiple sites or just not commit the transgression of hardcoding something that really doesn’t need to be hardcoded.

Here’s the complete code sample. Note there’s no need to bother with show_home at all.

wp_page_menu(array(
    'exclude' => get_option('page_on_front'),
));

The (highly biased) case against CSS preprocessors

Everybody who’s anybody is using CSS preprocessors!

Or so it feels. I’m an old-school vanilla CSS curmudgeon, and the more I’ve dipped my toes into working with CSS preprocessors (specifically, SCSS with Compass), the less I like them.

As I see it, there are three main problems with vanilla CSS:

No variables. Honestly this is probably the only problem I really have with CSS. I’d like to be able to set variables for things like colors that I use throughout a site. To a lesser extent, I see the benefit of “mixins” — reusable chunks of CSS.

Redundant code. It really depends on how you conceptualize your CSS structures, but it is very easy to fall into a habit of writing the same CSS code over and over again, resulting in bloated, hard to maintain files. While I am guilty of this just like anyone else, I find that if you format your CSS code properly you can combine properties efficiently to avoid redundancy without needing any external solutions.

Lack of programmatic logic. Here I’m thinking about things like conditional statements, and also math operations. This is probably as much of a strength as a weakness. CSS is a stylesheet, not a program. It’s a set of rules to be applied to formatting a document. There’s nothing programmatic about it. But still, as CSS selectors become more complicated and convoluted, it is clear that in some cases light programming logic would be helpful.

The real question is, do CSS preprocessors actually solve these problems? Or, more specifically, do they solve them without introducing new problems that are at least as bad as the ones they’re trying to fix?

For me the answer has been, and continues to be, no, they don’t. But I’m trying to get a more tangible explanation for why that is, rather than the simple gut feeling that’s been driving me away from using them up to this point.

What are other people saying?

My first stop in trying to answer this question of why I dislike CSS preprocessors was Google. I wanted to see what other people were saying, pro and con. Here are some interesting blog posts I found, going back a few years to the early (or at least earlier) days of CSS preprocessors:

The problem with CSS pre-processors
This article by Miller Medeiros was the first one I came across a few months ago when I initially pondered this question, and at the time it was all I needed to satisfy myself that I was not crazy for wanting to avoid CSS preprocessors.

So, assuming preprocessors do solve the problems with vanilla CSS, what are the problems they introduce? And how bad are they, really?

I need to get specific to my own situation for a minute here. I have a former coworker who is a firm believer in SCSS, and now that he’s gone, I’m left to maintain and extend the code he was writing. This experience casts my aversion to CSS preprocessors into stark relief.

Maintenance can be a challenge

The most obvious issue with using a preprocessor is that the output CSS is not exactly easy to hand edit, and worse, you shouldn’t hand edit it, because your changes don’t end up back in the original SCSS (or whatever format you’re using) files. If someone else goes back in later and edits the original SCSS and generates new CSS, your changes will get lost.

But let’s set that matter aside for a minute. In a broader sense, one of the key challenges for any web developer is to build code that is easy to maintain. Not just for you to maintain, but for whoever comes after you to maintain. Face it, you’re not going to be working on this project forever. At some point, someone else is either going to need to take it over, or throw away what you did and start fresh.

If you’ve ever jumped into an existing project midstream, or been handed the task of maintaining something someone else built — especially if it’s something built by someone who is no longer around to answer your questions — you know that it’s rarely an ideal situation. Even if the previous developer left copious documentation, it can take hours of picking apart their code to really get a firm understanding of how it all works. This is true with plain CSS too, but at least with plain CSS it’s a lot less work to track down a particular piece of troublesome code.

It’s non-standard

What happens when certain features of your favorite preprocessor get rolled into a future version of vanilla CSS? What happens if similar (but incompatible) features of a different preprocessor become the standard? In short, what if everything you’re doing right now becomes obsolete? How long are you going to hang on to doing things your old way with your no-longer-relevant preprocessor, before you have to scrap it and start over, or at least rewrite big chunks of your code to fit the new way everyone is doing things?

Call me a curmudgeon, but having been a professional web developer for over 18 years I’ve seen a lot of technologies and design trends come and go. I’ve always been skeptical of anything non-standard. I never used VBScript or ActiveX, I never embraced Flash, and in general I’ve done everything I could to both champion and adhere to open standards as much as possible throughout my career.

Suffice to say, resisting CSS preprocessors is just in my blood. They just don’t feel right to me. I’d rather do without features I want, if they’re not part of the standard, than resort to a non-standard workaround to make them happen… especially if it looks like there’s a reasonable chance they’ll be added to the standard at some point in the not-too-distant future.

Responsive images with srcset in WordPress

As a developer, I am somewhat conservative. I believe strongly in the importance of web standards, and I am reluctant to be an early adopter of any new techniques or, even worse, non-standard workarounds for limitations in existing standards. I’d rather live with the limitations until a proper standard — or at least a de facto standard — takes hold.

One of the latest issues to challenge my approach has been responsive images. I’ve settled into a pattern of going with “1.5x” quality images, trying to strike a balance between quality on large high-res displays and a reasonable file size. But it really doesn’t do either very well.

Today’s issue of A List Apart features an exciting article:

Responsive Images in Practice

Yes! In practice! Let’s do this!

There have been a couple of competing proposals for handling responsive image sets, and I am pleased to see the srcset attribute begin to emerge as the winner. The biggest plus it has for me is that it degrades gracefully for older browsers that don’t support it.

Well, before I had even finished reading the article I started thinking about how I could leverage the build-in image sizing mechanism in WordPress to use srcset. I haven’t looked around — I’m sure someone else has already created a plugin that perfectly nails what I am attempting to do here. And, to be honest, I haven’t extensively tested this code yet, although I did drop it into a site I’m currently working on, just to be sure it doesn’t throw a fatal error and that it actually does render the HTML <img> tag as advertised.

function img_with_srcset($attachment_id, $default_size='medium', $echo=true) {
  $output = null;

  // Get image metadata
  $image = wp_get_attachment_metadata($attachment_id);

  // Set upload directory for image URLs
  $upload_dir = wp_upload_dir();
  $upload_url = $upload_dir['baseurl'] . '/' . dirname($image['file']) . '/';

  // Build array of sizes for srcset attribute
  $sizes = array();
  foreach ($image['sizes'] as $size) {
    $sizes[$size['width']] = $upload_url . $size['file'] . ' ' . $size['width'] . 'w';
  }
  
  // Sort sizes, largest first
  krsort($sizes);

  // Get image alt text
  $image_alt = get_post_meta($attachment_id, '_wp_attachment_image_alt', true);

  // Generate output <img> tag
  if (!empty($sizes)) {
    $output =  '<img srcset="' . implode(', ', $sizes) . '" ' .
               'src="' . $upload_url . $image['sizes'][$default_size]['file'] . '" ' .
               'alt="' . esc_html($image_alt) . '" />';
  }
  
  // Return/echo output
  if ($echo) {
    echo $output;
    return true;
  }
  else {
    return $output;
  }
}

Let’s just examine what’s going on here.

The function takes three input parameters. An attachment ID, a default size (for the old school src attribute), and a boolean for whether to echo the output or just return it.

First, we get the attachment metadata and put it into $image. You can see more about what the wp_get_attachment_metadata() function does here.

Next, we set up the $upload_url variable to be the full base URL to the WordPress uploads directory. That’s because the metadata output only includes the filename of each sized image, not its full URL.

Then we loop through all of the sizes in the metadata output, generating a series of strings containing the image URL and its width, for use in the srcset attribute. We put these into an array because we need to manipulate the list a bit: we need to sort it so the largest images come first, and then later we need to implode() this into a comma-separated string.

Of course we also need the image’s alt text, so we grab that with get_post_meta() which you can read more about here.

Finally, assuming we actually have some size data, we build the <img> tag, complete with srcset attribute! Then we either echo or return it, as determined by the $echo input parameter.

Something else I’d like to try with this is taking it a step further by adding a filter that processes page content, looking for <img> tags, and automatically inserts the appropriate srcset attribute.

There you have it. I welcome anyone who’s reading this to give the function a try in your WordPress site, and let me know how it goes!

WordPress tip: A simple way to search all post types

I love WordPress, but its huge designer/developer community and extensible structure have made it possible to over-engineer a solution to just about every problem. And then under-document that solution.

Case in point: today I needed to add the ability to search across custom post types, along with pages. But by default search only searches posts. (That is, the “post” post type. Are you with me?)

This isn’t a new problem, even to me, although very few of the sites I build have (or need) internal search. It’s just not that useful on a site that doesn’t have hundreds of pages or posts, and most of the sites I build don’t.

In the few times in the past when I needed to be able to search across other post types, or other content like taxonomy data, I’ve relied on the Search Everything plugin. And judging by the fact that (as of today) it’s been downloaded 555,309 times, clearly I am not alone.

It’s a pretty good plugin, as plugins go. But it can be overkill, especially if all you need is the ability to search other post types.

And that’s where we run into the real, multifaceted problem with WordPress for developers: 1) there’s a plugin (no, make that dozens of plugins) for just about every obscure task, and 2) there are also several ways to go about building your own custom solution, especially if you’re building your own theme, but 3) the documentation is all over the place, and none of it is comprehensive.

Granted, by offering a targeted solution to a very specific problem in this blog post, I’m contributing to that documentation fragmentation, but whaddayagonnado.

There’s a fourth (and probably even more important) facet as well: plugins are developed independently by countless individuals (of varying degrees of skill), and it’s impossible for anyone to test them all for interoperability. The more plugins you install — especially if they’re excessively complex for the problem you’re intending to solve — the greater the chance you’ll introduce an incompatibility that will break your site. So it’s in your best interest to try to keep things as simple as possible. (And to err on the side of installing fewer plugins.)

tl;dr

If I understand correctly, every parameter in WP_Query can be passed in the query string, which means you can add corresponding input fields into searchform.php in your theme to modify the search functionality.

OK, now that was too simple (and abstract). Give me an example I can work with.

Here’s a one-line solution to get WordPress to search all of your post types (even custom post types), not just “post”-type posts. Add this into the form in searchform.php:

<input type="hidden" name="post_type" value="any" />

Guess what… you can also specify multiple specific types of posts using PHP’s method of using square brackets in your input name to pass in data as an array, like this:

<input type="hidden" name="post_type[]" value="foo" />
<input type="hidden" name="post_type[]" value="bar" />
<input type="hidden" name="post_type[]" value="baz" />

A caveat: I tried the above with page as one of the values and it didn’t work; it showed my custom post types, but not “page”-type posts. I suspect it’s because that’s one of the predefined type parameters that make the query behave slightly differently. So this solution isn’t perfect, but using any as the value will work: it gets “post”, “page” and your custom post types.

My goal was to have a simple search form that would just search all post types, so I made this a hidden field, but you could make it radio buttons, checkboxes or a select menu if you wanted to let the user pick, and this just scratches the surface of what you can do to customize your search form to leverage the capabilities of WP_Query.