When switching servers breaks code: a WordPress mystery

Earlier this week I launched a brand new WordPress site for a long-time client. Break out the champagne! But of course it’s never that simple, is it?

The client’s live server is a newly configured VPS running Ubuntu 16.04 LTS and PHP 7.0; meanwhile, our staging server is still chugging away on Ubuntu 14.04 LTS and PHP 5.5. So, clearly, a difference there. But I was pleased to find that, for the most part, the site functions perfectly on the new server.

But then the client discovered a problem: on one page, content from a custom post type query wasn’t displaying.

Here’s a short version of the pertinent code:

$people = new WP_Query(array(
  ‘order’ => ‘ASC’,
  ‘orderby’ => ‘menu_order’,
  ‘posts_per_page’ => -1,
  ‘post_type’ => ‘person’,
));

if ($people->have_posts()) {
  while ($people->have_posts()) {
    $people->the_post();
    ?>
    <article>

      <header><h2><?php the_title(); ?></h2></header>
      <div><?php the_content(); ?></div>

    </article>
    <?php
  }
}

Strangely, the_title() was working fine, but the_content() wasn’t. It had been — still is, in fact — working on our staging server, all other things within the WordPress context being equal. (Identical, up-to-date versions of the theme files and all plugins, and WP itself.) And the client confirmed that the content was present in WP admin.

I found, confusingly, that get_the_content() works, even though the_content() doesn’t. But of course you don’t get all of the proper formatting (like paragraph breaks) without some WP filters that the_content() applies, so I tried this:

<?php echo apply_filters(‘the_content’, get_the_content()); ?>

Still didn’t work. After a bit more research I was reminded that the pertinent function that filter runs is wpautop(), so I just called that directly:

<?php echo wpautop(get_the_content()); ?>

Now I have the content displaying nicely, but this is clumsy and I really do not get what might be different. I know the new server is running PHP 7.0 and our staging server is running PHP 5.5… but I’m struggling to understand what kind of changes in PHP could cause this specific problem.

Since get_the_content() works, and the_content() doesn’t, the problem has to lie in something that’s happening with the filters on the_content(). Why? Because the_content() calls get_the_content() right up front. In fact, there’s not a lot to the_content() at all. This function lives in wp-includes/post-template.php (beginning at line 230 in WP 4.6). Here it is in its entirety (reformatted slightly for presentation here):

function the_content( $more_link_text = null, $strip_teaser = false) {
  $content = get_the_content( $more_link_text, $strip_teaser );

  /**
  * Filters the post content.
  *
  * @since 0.71
  *
  * @param string $content Content of the current post.
  */
  $content = apply_filters( ‘the_content’, $content );
  $content = str_replace( ‘]]>’, ‘]]>’, $content );
  echo $content;
}

As you can see, it’s really just 4 lines of actual code. It calls get_the_content() to retrieve the content, applies filters, does an obscure string replacement (which I think I understand but is not really pertinent here), and then echoes the results out to the page.

It’s pretty clear to me that the problem has to lie in one (or more) of the filters in the 'the_content' stack. I have to admit that even after years of working with it, I only have a rather nebulous understanding of how hooks work, so I’m not even sure where to begin dissecting the filter stack here to pinpoint the source of the trouble.

Whenever I know something works in one place and doesn’t work in another place, the first course of action in troubleshooting is to try to identify all of the differences between the two environments. Obviously we have some big differences here as I noted at the top of this post. But I am going to assume that the problem does not lie at the OS layer. Most likely it’s either a difference between PHP 5.5 and 7.0, or, even more likely, a difference between the PHP configurations on the two servers… specifically, modules that are or are not active. See my previous post on The Hierarchy of Coding Errors for my rationale here. Also keep in mind that I personally was responsible for installing LAMP on the server and configuring PHP, and it’s pretty obvious that we’re looking at the sysadmin equivalent of #1 or #2 in that list.

The next step, were I to care to pursue it much further (and if I didn’t have 200 other more important things to do, now that I have the problem “fixed”), would be to run phpinfo() on both servers and identify all of the differences.

That’s one possible path, at least. Another thing to consider is that the_content() actually is working just fine in other parts of the site, so maybe it would be worth digging into that WordPress filter stack first.

At this point, because as I said I have a few other more important things to work on, I will probably leave the mystery unresolved here. But I’d welcome any ideas from readers as to an explanation for all of this.


Update! I just couldn’t leave well enough alone, so a few minutes after I published this post, with the client’s permission, I restored the old version of the template, turned on WP_DEBUG and installed the Debug Bar plugin. Jackpot! Debug Bar returned the following error message when I was calling the_content(), but not when I had my “fixed” code in place:

Screen Shot 2016-09-01 at 9.24.16 AM

Well, how about that? As it turns out, the problem is due to a filter I myself had added, using a previously written function. (That’s #3 on the hierarchy list.) Combine that with deprecated functionality that was removed in PHP 7.0, and problem solved. And I even figured out why the problem is only occurring on this page and not site-wide… because my filter only runs if there’s an email address link in the content.

A follow-up on Apache not starting on my web server

About 6 weeks ago, I wrote about a problem I was having with Apache not starting with SSLEngine on. I ended the post somewhat ominously with the following:

I’m a little concerned that Apache is going to require manual input of these pass phrases again whenever it restarts (e.g. if the server reboots). I hope not, but for now I am at least able to move forward knowing it works at all.

This morning, a little before 6 AM, that happened. I was awakened by notifications (with their attendant beeps and nightstand vibrations) on my iPhone that my web server was down. Great. Half-awake, I fired up my hosting provider’s handy iPhone app, tapped the “Hard Reboot” button, and tried to go back to sleep. Except, the notifications kept coming. Eventually I was awake enough to realize that the server was coming back up, but Apache wasn’t. Time to get up and deal with this problem from a real computer.

SSHed in, I tried manually starting Apache, and got this:

(98)Address already in use: make_sock: could not bind to address 0.0.0.0:80
no listening sockets available, shutting down
Unable to open logs

What the crap? After spending a half hour visually scanning log and configuration files, to no avail, I decided I needed to try to find out what was running on port 80. This page was helpful in that regard. I ran the command lsof +M -i4 and found that, whaddayknow, Apache was running. Apparently. But I couldn’t shut it down, and I couldn’t restart it. There were no signs of any compromise of the system’s security, so I just chalked this up to some minor problem deeply buried somewhere in a configuration file that I have yet to track down (but which is probably my fault). At any rate, lsof gave me what I really wanted: the process ID that was listening on port 80. Time for the dreaded kill -9 command.

After that, I tried starting Apache again, and it worked… and, as I suspected, it did ask for the pass phrases again. But now, all is well. (Except for the nagging feeling of not knowing what caused this to happen in the first place. Stay tuned…)

My strange solution to Apache not starting on Ubuntu Linux server with SSLEngine on… (YMMV)

The situation: I’m running a web server on Ubuntu Linux using Apache 2. I have two sites on the server that need SSL. I obtained a second IP address (since you can only have one SSL certificate per IP address) and configured Apache accordingly. I was able to get regular old port 80 non-SSL pages to load just fine on virtual hosts configured to use both IP addresses.

I created my key files, got the certificates from the CA (GeoTrust, in this case), all that business. Put the files in the right places, configured the Apache files, all that jazz. Made sure mod_ssl was enabled, yes. All of that. Trust me, I did it. Don’t bother asking. And yet, whenever I tried to run Apache with SSL configured… nothing.

And I mean… nothing.

I’d restart Apache at the command line, and nothing. No error messages of any kind. But Apache wasn’t running. I checked all of the log files (and I mean all of the log files), nothing. DOA.

Eventually I tracked down the culprit as the SSLEngine on line in the Apache config file. With it in there, Apache wouldn’t start. Comment it out, Apache starts up just fine, but of course you don’t have SSL.

I’m using the arrangement of Apache config files as they’re installed in a default Ubuntu build. That means /etc/apache2/httpd.conf is actually empty, and most of its usual contents are in /etc/apache2/apache2.conf, with a few other settings dispersed into a number of adjacent files. There are some critical settings in /etc/apache2/ports.conf and then everything else is in the individual config files I’ve created for each site on the server, stored in the /etc/apache2/sites-available directory with symbolic links for the active ones in /etc/apache2/sites-enabled.

Well… that turned out to be the problem. I’m not sure why it matters, but I was putting the VirtualHost configurations for the SSL sites in the respective sites’ existing configuration files. But no… all of the SSL-related (port 443) <VirtualHost> blocks needed to be put in the 000-default file. That made all the difference.

Well, almost all the difference. My private key files are encrypted with pass phrases, and Apache needed me to enter them when starting up. But, funny thing… it didn’t ask me for them all right away. I had to fiddle around with starting and stopping it a couple of times (which I bothered to do because it still wasn’t running), but eventually it did ask me to enter the pass phrase for both sites, and after I did that, everything is working. Both SSL sites, all of my non-SSL sites, it all works.

I’m a little concerned that Apache is going to require manual input of these pass phrases again whenever it restarts (e.g. if the server reboots). I hope not, but for now I am at least able to move forward knowing it works at all.

Sure, it’s pointless, but… well… that’s the point

I have a pair of old Macs that have been sitting unused, or almost unused. The “hemisphere” iMac G4, dating back to 2002, has been the kids’ computer, sort of… except for the fact that they don’t really ever use it. And the “toilet seat” iBook G3, from 2000, has been gathering dust in our bedroom closet for the past year or so, since I tried and failed to install Ubuntu 7.10 on it.

Today various factors came together to lead me to bring the iMac, and the desk it was sitting on, down from the kids’ bedroom and into my office. Now that I have it, I might as well do something with it. And that something is installing the PowerPC version of Ubuntu 8.04. And as long as I had set up desk space for antiquated Macs, I lugged out the ol’ toilet seat and decided to, at the very least, get it back up and running with an OS it was more comfortable with, that being Mac OS 9.1. (I’m working on upgrading it to 9.2.2 at the moment, but 9.1 was the most recent “Classic” installer disc I had on hand.)

And all of this leads to the following, most improbable of photographs. What’s the point? Well… I got to take this photo! Is that point enough for you?

iMac G4 running Ubuntu 8.04, and iBook G3 running Mac OS 9.1

What’s next for these two old beasts? Well, I’m going to boot up the Ubuntu Live CD on the iBook, just to see if 8.04 is more friendly to it than 7.10 was. If so, I’m going to install Edubuntu and make it the kids’ new computer. If not, well at least it’s got a stable OS now, and I’ll still make it the kids’ new computer. I can probably round up some pre-OS X kids’ software for them, and they can always use it to watch DVDs.

Meanwhile, the iMac is possibly going to turn into a local file/media/web server, or at least be another system for me to play around with Linux on. I do have Ubuntu 8.10 on my main MacBook, but having to reboot into it is usually more trouble than it’s worth.

Update, a few minutes later: I went for it with the Live CD on the iBook. Good news. After a few fretful minutes watching the display do some very weird things during the boot process, I stepped away to deal with some kid antics. I came back to the iBook to see this:

Ubuntu 8.04 running on a "toilet seat" iBook G3.