Two bad lines of code took this entire site down. Here is what you can learn from my mistake.
Table of Contents
Here is What Happened
Apparently, at some point late Friday night, my hosting provider upgraded to a newer version of PHP. When I checked my site Saturday morning, all I could get was “There has been a critical error on your website.” in a neatly-formatted box.
Uh oh.
Here is What I Learned, and How I Fixed It.
I had an older table of contents plugin that used deprecated syntax for accessing characters within a string, and that older syntax is now no longer supported in the newer version of PHP:
Deprecated Syntax: MyString{Index} Proper Syntax: MyString[Index]
The plugin in question used the deprecated syntax in two places, which was now throwing a hard error instead of just ignoring as it had previously done.
Even after I fixed the two syntax errors, I had some kind of weird memory allocation problem, so I ended up just disabling the plugin, which at least restored my site.
As it turns out, the plugin I’m using is no longer being maintained. Even if I fix this problem, I run the risk that I will have some other problem later, for the same reason.
So rather than fix someone else’s old code or write my own, I searched for a replacement. At least for now.
Ideally, I wanted an exact replacement:
- Light weight and simple to use
- Free for non-commercial use / GPL / LGPL
- Same integration features – namely via “toc” shortcode
- Same functionality:
- Produces a table of contents automatically by selectively including header styles and other styles
- Produces multi-level section numbering (e.g. 1, 1.1, 1.1.1, etc…)
- Prepends the section number in front of the actual header text within the body of the post
To my surprise, there are not many options that are free AND simple AND work as requested, but I finally found one that was close. Although the plugin builds the table as expected, it doesn’t number the header text within the body.
So, I added some CSS numbering, only to find out that WordPress uses some of the same header styles to render the page itself – for example, the post title uses <H2>, and so does the blog’s tagline. So some selective CSS numbering later, I finally got it working.
For reference, in case anyone needs it:
body { counter-reset: h2cc; /* In theory, I don't need h3 through h6 here, because I'm resetting the next level down within the header itself. However, this is the only way I could get it to work properly */ counter-reset: h3cc; counter-reset: h4cc; counter-reset: h5cc; counter-reset: h6cc; } h2 { counter-reset: h3cc; } h2:before { content: counter(h2cc) ". "; counter-increment: h2cc; } h2.entry-title:before { /* Special case for post title. Because this hits AFTER the body, I had to add a negative increment, or my numbering started with 2. */ content: none; counter-increment: h2cc -1; } h2#site-description:before, h2.widget-title:before, h2#comments-title:before { /* Special cases for tagline, widget (side bar) titles, and comment section title. */ content: none; } h3 { counter-reset: h4cc; } h3:before { content: counter(h2cc) "." counter(h3cc) ". "; counter-increment: h3cc; } h3#reply-title.comment-reply-title:before { /* Special case for each comment's title. */ content:none; } h4 { counter-reset: h5cc; } h4:before { content: counter(h2cc) "." counter(h3cc) "." counter(h4cc) ". "; counter-increment: h4cc; } h5 { counter-reset: h6cc; } h5:before { content: counter(h2cc) "." counter(h3cc) "." counter(h4cc) "." counter(h5cc) ". "; counter-increment: h5cc; } h6:before { content: counter(h2cc) "." counter(h3cc) "." counter(h4cc) "." counter(h5cc) "." counter(h6cc) ". "; counter-increment: h6cc; }
The Moral of the Story
I run in to situations all the time where old code is no longer being maintained, and therefore can’t be upgraded to newer operating systems, databases, nor patched to current because the code breaks.
“Just run the old code inside an older environment”
– Developer mistake #101
Although this is a short-term fix – I could have downgraded to an older PHP – it doesn’t solve the underlying problem, which is that the threat landscape is constantly changing, and the only way the vendors can keep up is to deprecate older operating systems and components. They shouldn’t be expected to fix a brand-new problem on a component which itself is now many versions old.
The only viable approach is to ensure that every bit of code you are using is currently being maintained. From the code within your application, to the code inside your operating systems and databases, everything needs to be supported.
- Bring older code up to date with newer standards
- Replace older components with newer ones
- Plan for life cycles and future standards
After having written quite a bit about developer mistakes, I was surprised that I made this simple mistake. Although I don’t run any kind of critical code, and at the end of the day, the only impact was that my website was down for a few hours, I wanted to share my experiences and lessons learned.
If you want to read about other common developer mistakes, here is a list:
- Top Developer Mistakes
- More Common Developer Mistakes
- Common Website Design Mistakes
- The Log4J Problem Was Both Insidious And Unnecessary