I know, I know, I’ve ranted before about code quality, but today I want to focus more on how we, as WordPress theme and plugin developers, write HTML.
Don’t print out too early
We’ve all been there: You’ve happily opened your PHP tag,
<?php, at the beginning of the file, at character #1. Your file is going to contain only code, no markup. Perhaps the file is included before any HTML output has even begun.
Being the savvy PHP developer that you are, you know all too well, that if your code were to output even one extra white-space, that would screw up the page’s markup. You’re careful not to use any closing
?> tag at the end of the file, to avoid any mishaps. Even a stray linefeed character could trigger output buffering early, and then out goes any chance for other code to modify the HTTP response headers, among other things.
So now you’re happily defining your functions, classes and other code-y stuff, then all of a sudden, you need to build some markup! Perhaps you’re printing out a UI element, maybe it’s a widget, maybe it’s a shortcode, maybe it’s even an RSS feed or other XML, but in any case, it’s too small for you to define an entire template-part. Your string is going to be some concatenation of hard-coded markup and dynamic data that’s currently sitting in variables.
How To Meet Ladies
Everyone says they know HTML. But HTML is easy to get started with, and hard to master.
When writing HTML markup for a theme or plugin in WordPress, your professional-grade code must fulfill a number of simultaneous requirements. Your main concerns should be to:
- Write correct HTML5 markup that is SEO friendly, using semantic tags where possible (e.g.
- Escape any values properly
- Internationalize strings so they can be translated
- Give unique IDs to your elements, and name your classes properly, to assist any CSS and JS assets that go with your markup. Remember, naming things is one of the two hard things in computer science!
- Conform to the WordPress HTML Coding Standards. This is a good standard to follow, because it forces you to be consistent about how to open and close your PHP tags, among other things.
- Depending on use case, optionally add semantic metadata, such as microformats.org, schema.org, Open Graph, ARIA, etc
A concrete example
So let’s say you want to output some HTML form when a shortcode is used. We’ll give the form a unique ID and we’ll also embed some default values, coming from the shortcode’s attributes.
Don’t do this:
You might be tempted to do the following:
$id = uniqid( 'form' );
$html = '<form id="' . esc_attr( $id ) . '">';
$html .= '<input type="text" name="name" placeholder="' . esc_attr( 'Enter your name', 'langdomain' ) . '" value="' . esc_attr( $atts['name'] ) . '" />';
$html .= '<input type="number" name="age" placeholder="' . esc_attr( 'Enter your age', 'langdomain' ) . '" value="' . absint( $atts['age'] ) . '" />';
$html .= '<button type="submit">' . esc_html( 'Submit', 'langdomain' ) . '</button>';
$html .= '</form>';
Sadly, a lot of people would say this is fine! I can’t blame them too much. We’re all way too used to opening the PHP tag and then never closing it again: we tend to use PHP as if it was Java. And with so many PHP templating libraries out there, it’s hard to remember that PHP is primarily a templating tool.
Do this instead:
We can combine the awesome templating power of the language with some cleverly nested output buffering, and now the above can be re-written as follows:
$id = uniqid( 'form' );
<form id="<?php esc_attr_e( $id ); ?>">
<input type="text" name="name" placeholder="<?php esc_attr_e( 'Enter your name', 'langdomain' ); ?>" value="<?php esc_attr_e( $atts['name'] ); ?>" />
<input type="number" name="age" placeholder="<?php esc_attr_e( 'Enter your age', 'langdomain' ); ?>" value="<?php esc_attr_e( $atts['age'] ); ?>" />
<button type="submit"><?php esc_html_e( 'Submit', 'langdomain' ); ?></button>
To see a somewhat more complete example, here’s the above as a gist:
Notice how we start a new output buffer with
ob_start() and how we then get the resulting string with
ob_get_clean(). Notice also how we’ve swapped
esc_attr_e(). Similarly, we would swap
checked( $value, true, false ) with
checked( $value, true ), and so on.
PRO TIP: If your code throws an exception, you can use
ob_end_clean() in your
catch clause to cancel your buffer.
“Why does it even matter”, you ask?
Well, there’s a few advantages with the second form of our, err…, form!
- Readability. I find the second piece of code to be much more readable.
- Syntax coloring. Yes, some editors do perform HTML parsing and show visual queues related to the syntax of HTML inside strings. But not every editor does this, and the ones that do, cannot do this perfectly.
- No quote hell. No need to count opening and closing
'characters, interpolated with
"characters while printing HTML attributes. This business can quickly get confusing, and is a common source of errors.
- Show off your mad PHP output buffering skillz! Your average front-end developer will be astonished at your professional-looking code!
Now, if only we were allowed to use shorthand PHP tags, our code could be even nicer. Sadly, we can’t.