Blog

I’ve been attending WordCamp Atlanta since 2013, and it’s been one of my favorite annual WordCamp events. It is larger than WordCamp Orlando, with an average of 600 attendees to our 350, but it rarely feels large with the sensible layout of the venue and separation of spaces. Everything is in one building across two floors, and all of the rooms are near each other.

The ease of getting around, and the proximity of hundreds of WordPress people without a feeling of claustrophobia makes it an ideal setting for conversations. We call the space between sponsor tables and session rooms the “Hallway Track”, since it can be a valuable session space itself. I can talk with friends that I see a handful of times per year, or find out what other companies in the space are up to.

WordCamp Atlanta 2019 Sponsor Area

My Workshop – Building a Plugin

Recently I’ve been having success at events teaching attendees how to build their own plugins and themes. I was under a new constraint this time, of offering my plugin workshop in a 50 minute time-slot as a lecture, where it’s been a two to three hour workshop in the past. Treating it as a lecture meant no hands on, one-on-one help, but it let me present the information at a comfortable speed.

The questions that I got, both immediately following my session and throughout the weekend, indicated that I was able to help some of the attendees. I was told by three separate people that they attended the getting started workshop the day before, and my lecture put that information in place for them in an understandable way.

I’m not always confident when I give presentations, as listening to myself drone on for more than a few minutes feels excessive to me, and I can only imagine what others think. Having thoughtful followups made me feel that I provided value.

Code for my workshop can be found on my Github.

Sessions

WordCamps are a great place to learn more about WordPress, but also to learn about related topics, such as SEO and marketing, running a business, or developing applications. We hold a unique position in tech in that our tool serves users at all ends of the technical spectrum. The lower barrier of entry to starting your first WordPress site coupled with the flexibility and extensibility of the platform makes it an ideal way for people of various skills to interact on a common ground.

I only attended a handful of sessions other than my own, preferring to spend time in the Happiness Bar offering help, as well as the aforementioned conversation time. Here are a few of my highlights:

  • Getting confirmation from Tom McFarlin, a developer who I greatly respect, that WordPress can serve as an application foundation. I’ve wasted some time that I could have been working on a variety of projects wondering if I’m just trying to fit a peg into a WordPress shaped hole, forgetting that getting something done at all is better than an optimized nothing.
  • Being reminded by Adam Walker, co-owner of Sideways8, that routines, habits, and processes are key when it comes to managing your work life. I’m impressed with the number of projects that he handles while maintaining a balance that leans favorably toward family and personal life. Sometimes you just need to hear the same message in a new way or for the tenth time before it sinks in. I’m making some changes based on his presentation, which he shared on his site.
  • Getting some ideas on ways to automate my development workflow from Chris Wiegman, a personal friend and team lead at WP Engine. This is one of the places that I feel that I could improve most when it comes to my processes. Some of the tooling that Chris uses is beyond me currently, but I want to expand my toolset. Chris also shared his slides on his site.

The rest of the event

I got to hang out with lots of WordPress friends and meet a few new people this weekend. I try not to only talk to people that I already know, since that leaves out all of the people who would be good friends if I took the time to get to know them now. I also shared dinner, lunch, coffee breaks, and walks around town with fellow attendees.

The real value of these events for me is the personal connection, where I get to talk one-on-one with someone a step ahead of or behind me in the business and product building process. We’re all learning this as we go, and it’s good to be reminded that no one comes in with all of the knowledge, and no business starts fully-formed.

WordCamp Atlanta 2019 Tips and Tricks Boards

WordCamp Atlanta made these great boards for people to post tips and tricks around business, WordPress, and life. I wish I’d gotten a picture at the end of Sunday!

On the secondary value front, I won an IKEA gift card from the folks at GoDaddy Pro! I don’t usually enter contests at WordCamps, but I’m glad that I entered that one and was still in town during closing remarks. We’ve been talking about getting a new couch at home for a while, and this is the push to make that purchase happen.

A big thanks to SiteGround!

Finally, I want to thank SiteGround yet again for helping to sponsor my trip. I realize that I haven’t yet written a post on the SiteGround Ambassador program, which is something that I’m going to fix now.

I met three members of the SiteGround team that I haven’t yet had the chance to meet, spent some time at their booth, and discussed SiteGround services several times during the event. It’s very easy to do when the conversation comes up from whoever I’m talking to with general interest, and I don’t even feel like I’m giving a sales pitch. That said, I’d do a sales pitch anyway, since I truly enjoy the service and level of support.

SiteGround team at WordCamp Atlanta 2019
The SiteGround team is always a great WordCamp addition!

I also got to chat with Francesca Marano, the WordPress Community Manager at SiteGround. We chat online regularly, but in person opens up new space for the kinds of conversations that don’t regularly come up online. Again, these events are a great way to catch up and form deeper connection with the people who help make this community worth sticking around for.

I greatly enjoyed WordCamp Atlanta 2019, and look forward to another fantastic event in 2020!

An update to Yoast SEO v11.1 came out yesterday, causing a few site errors relating to illegal strings in PHP. It made me dust off this post to provide some detail on what that PHP warning is, why it is happening, and how it can be fixed.


Last year I updated all existing client sites that I could to PHP version 7.2, to replace versions 5.6 and 7.0, both of which reached their end of security update lifespans in December of 2018. The current plan for WordPress v5.2 is to drop support for versions of PHP below 5.6, which is targeted to be released on 7 May. If this goes well, the minimum PHP version will be bumped to 7.0 later this year.

We’re only a few weeks away from this change, and a lot of hosts have been informing users that their version will change, or that they should opt-in to update when they can. One issue is that there are some things that work in earlier versions of PHP that will now throw warnings, notices, and errors in newer versions. One of the ones that I had to contend with on a few sites recently was the “Illegal string offset” warning.

Warning: Illegal String Offset

Here’s a few warnings that appeared on a development version of a site that I was upgrading (file path removed for readability):

__Warning:__ Illegal string offset 'menu' in [file location] on line 13 __Warning:__ Illegal string offset 'post_types' in [file location] on line 25 __Warning:__ Illegal string offset 'post_formats' in [file location] on line 36

I’m noting that it’s a development environment, because I had WP_DEBUG set to true in my wp-config.php file, which I don’t do on live, production environments. Basically, I ensure that on a live version of a site I don’t have PHP errors/warnings/notices displayed, even if there are some that would otherwise display.

I took a look at that file, which was a configuration file for the theme being used. The relevant lines from that file are below:

/* * Theme menu */ $theme['menu'] = array( THEMENAME, 'Slideshow', 'Sidebars', 'Style', 'Upload your fonts', //'Help' ); /* * Post types */ $theme['post_types'] = array( 'Posts', 'Pages', 'Works', 'Testimonials', ); /* * Post formats * aside, gallery, link, image, quote, status, video, audio, chat */ $theme['post_formats'] = array( 'gallery' );

Can you spot the issue? I didn’t immediately see it myself, as I saw things like $theme['menu'] and thought “how can that be read as a string? The braces clearly indicate that we’re setting an array key.

Explicitly Declaring an Array in PHP

What I didn’t realize was that we were missing something that’s necessary as of PHP v7.1.0: an explicit declaration of the variable $theme as an array. If you take a look at the PHP.net manual entry on PHP Array Syntax Modifying, you’ll see the following note:

Note: As of PHP 7.1.0, applying the empty index operator on a string throws a fatal error. Formerly, the string was silently converted to an array.

So there’s our issue, and with it, a lead on a solution: the theme never explicitly declared the variable $theme to be an array, and so it was assumed to be a string. Since it is no longer being silently converted, we have a warning being thrown.

Fixing the Illegal String Offset Warning

The solution in this case is to add a line to the start of that block of code where we explicitly declare our variable as an array. What that looks like is this:

$theme = array(); /* * Theme menu */ $theme['menu'] = array( THEMENAME, 'Slideshow', 'Sidebars', 'Style', 'Upload your fonts', //'Help' );

By adding $theme = array();, we’re telling PHP, “yes, this is an array, please treat it as such.” It doesn’t have to try to guess what we mean, which newer versions of PHP no longer do anyway.

PHP v7.0+ also introduces strict typing, which is great for being even more explicit in your PHP coding. This makes the code more secure (people can’t put different data types in than you intend), and less liable to break (you will always know what type of data to expect). If you want to learn a bit more, Eric Mann wrote a short introductory post on the topic early last year.

PHP is getting better and better all the time, but this progress sometimes causes old code to break. While this is frustrating, it can also give you the opportunity to review old code with fresh eyes. It’s not always convenient to do this, but it can overall improve your site!

If you’re like me, you don’t do much for SEO on your site. If you’re a better marketer than me and also have tools that you use for SEO, you probably don’t use the built-in SEO tools with the Genesis Theme Framework.

The tools do their job and are already there if you want to use them, but they can be limiting, as well as duplicate work being done with any other SEO plugin that you may be using. You can choose not to use them, but they still take up some valuable space in your dashboard and while editing pages, and they can be a bit confusing if you’re handing the site off to someone else to manage.

WordPress Gutenberg post editor with Genesis SEO enabled
Look at all of that space devoted to an unused settings section!

Removing the Genesis SEO Settings

One of the many great things about Genesis is that it allows you to easily modify or remove various portions of it without having to directly edit the core files of the theme. This allows you to modify your child theme only, so that if you ever switch child themes or Genesis updates, your changes won’t break.

Place the following code in your functions.php file, or another file that loads on the dashboard.

// Remove Genesis SEO settings from post/page editor remove_action( 'admin_menu', 'genesis_add_inpost_seo_box' ); // Remove Genesis SEO settings option page remove_theme_support( 'genesis-seo-settings-menu' ); // Remove Genesis SEO settings from taxonomy editor remove_action( 'admin_init', 'genesis_add_taxonomy_seo_options' );

The first line of code removes the SEO metabox in posts/pages/custom post types. The post editor is already looking cleaner!

WordPress block post editor without Genesis SEO settings section
Now there’s less distraction while writing a post!

The second line of code removes the SEO settings menu from the left sidebar in the dashboard. If we’re not using it at all, no reason to have the settings page!

Finally, the last line of code removes the SEO settings from taxonomies. That means that you won’t be able to access them on categories, tags, or any other custom taxonomies on the site.

And with that, we’re done! Three lines of code (plus a bit of spacing and comments to make it easier to read and remember what we did that for later), and we’ve removed access to the Genesis SEO settings. Again, this isn’t a knock on Genesis, but simply a way to clean up your site a bit if you’ve already invested in another SEO tool for WordPress.

I’ll be honest: most of the posts that I write are either because I’ve solved a problem for a client, or because I solved a problem that Past-David created. This is one of those PD problems, where I wrote some code that stopped functioning. When I looked into it, it turns out that I was using the wrong function to test for a variable in PHP.

There are a variety of functions made to test the state and value of variables, including ones that can tell you if there is anything available to use at all. Three of these functions that are easy to mix up are isset(), empty(), and is_null().

Built-in Variable Testing Tools

All three of these functions are built into PHP, so they should always be available for your use when writing code. empty() and isset() are language constructs, while is_null() is a standard function. We’ll go over why that’s important later in the article.

Before I discuss the difference and show a few examples, here are the descriptions for empty(), isset(), and is_null() from the php.net manual.

empty()

empty ( mixed$var ) : bool

Determine whether a variable is considered to be empty. A variable is considered empty if it does not exist or if its value equals FALSEempty() does not generate a warning if the variable does not exist.

isset()

isset ( mixed$var [, mixed$... ] ) : bool

Determine if a variable is set and is not NULL.

If a variable has been unset with unset(), it will no longer be set. isset() will return FALSE if testing a variable that has been set to NULL. Also note that a null character (“\0”) is not equivalent to the PHP NULL constant.

If multiple parameters are supplied then isset() will return TRUE only if all of the parameters are set. Evaluation goes from left to right and stops as soon as an unset variable is encountered.

is_null()

is_null ( mixed$var ) : bool

Finds whether the given variable is NULL.

What’s the difference between these variable testing functions?

You can see from the above definitions that these three functions do similar, but not the same things. You’ve gotta determine if you’re trying to test for whether a variable is null, true or false, and whether the variable has been declared.

When to use empty()

If you are using empty() you can test if a variable is false, but also if the variable does not exist. This function is best used when you want to ensure both that the variable exists, and has a value that does not equal false. Note that PHP will treat empty strings, integers of 0, floats of 0.0, empty arrays, and the boolean value of false as false. So basically, only use empty() when you want to ensure that there is some actual value to the variable.

Since you don’t have to declare variables before using them in PHP, you can get in a position where you are trying to perform actions or run other tests on a variable that hasn’t yet been declared. While it’s best practice to declare your variables before use for this and other reasons, this gotcha is one of the reasons that empty() is used differently from isset().

When to use isset()

If you are using isset(), you can test specifically if the variable has been declared already, and that the value is not null. So as long as you have a declared variable that has a value set and is not of the value NULL, you’ll return true when you test it with isset(). This would be a good condition to check before doing other checks to perform actions on a variable:

// Declaring our variable $variable = 'Some String'; // Testing that our variable exists, then testing the value if ( isset( $variable ) && $variable !== 'Some Other String' ) { echo 'This code evaluates since both of the above are true'; }

In the above example, we’ve declared our variable as a string, then tested if the variable is set (it is), and if it is not equal to a different string (it is not). Since both of those tests are true, we would then echo out the sentence in that conditional statement.

Should you use is_null()?

Finally, is_null() works in a similar manner to isset() as its opposite, with one key difference: the variable must be declared to return true, provided that it is declared without any value, or is declared specifically as NULL.

I said above that isset() tests whether a variable has been set or not, which is true, but it can handle no variable being set and providing an output of false. That is helpful if somewhere else in the code the unset() construct has been used to remove a variable from scope entirely.

In contrast, is_null() would not only not properly evaluate, it would also return a notice due to its inability to evaluate. Usually that’ll look something like this:

Notice: Undefined variable: variable in /directory/to/code.php on line X

Since isset() is both a language construction, and can handle variables that aren’t declared, I’d generally recommend it over using is_null() in any situation. If you need to use is_null(), I might suggest finding a way to rewrite your code instead.

Language Construct vs. Built-In Function

I mentioned before that isset() and empty() are both language constructs in PHP, where is_null() is a built in function. Language constructs are reserved keywords that can evaluate whatever follows them in a specific manner. That means that it already knows what to do without having to find the definition of the construct like it would a function.

The main things to keep in mind between the two when evaluating your code is that language constructs in PHP are slightly faster (but honestly not enough to worry about for speed optimization), they can’t be used in variable functions, and they don’t throw any errors when evaluating variables that don’t exist.

Many times I see warnings and notices because a variable hasn’t been declared, and no one has confirmed that the variable already exists before trying to do some other conditional check with it. Using isset() and empty() can go a long way to avoiding those errors.

Examples of output of these three functions

The following table has been taken directly from a demo created by Virendra Chandak on his personal site. You can view the demo here.

Value of variable ($var)isset($var)empty($var)is_null($var)
“” (an empty string)bool(true)bool(true)bool(false)
” ” (space)bool(true)bool(false)bool(false)
FALSEbool(true)bool(true)bool(false)
TRUEbool(true)bool(false)bool(false)
array() (an empty array)bool(true)bool(true)bool(false)
NULLbool(false)bool(true)bool(true)
“0” (0 as a string)bool(true)bool(true)bool(false)
0 (0 as an integer)bool(true)bool(true)bool(false)
0.0 (0 as a float)bool(true)bool(true)bool(false)
var $var; (a variable declared, but without a value)bool(false)bool(true)bool(true)
NULL byte (“\ 0”)bool(true)bool(false)bool(false)

Recently, I helped a client import a large set of addresses into a location plugin for WordPress. The import mainly went smoothly, but we noticed some issues when searching in areas with zip codes leading with one or two zeroes. The addresses weren’t coming up as they should.

After examining some of the imported addresses, we realized that all of the leading zeroes were being stripped, and we could no longer search by those zip codes. I’m going to give a brief overview of why this happened, and how I solved it. Hopefully it helps if you need to make this kind of update to a WordPress database too!

Why is this happening?

Some programs “helpfully” strip leading zeroes from numbered cells, including Excel, Numbers, and Google Sheets. This means that 04102 in Portland, Maine becomes 4102, which isn’t a zip code in the US.

The same could happen upon import into the database, depending on how the import is done. In either case, I’m working with an import that’s already complete, as opposed to having caught this issue before the addresses were added to the site. I don’t want to remove all other relevant content just to import again and fix these zip codes, so I’m going to go directly to the database to solve the problem.

How to fix the missing zeroes

There are several ways to add the zeroes back, but most places that you search will suggest changing the datatype of the zip code column, which doesn’t help when it’s in WordPress where we can’t modify that when there is other info stored in the same place. Plus some zip codes have the full nine digit route number depending on where the data was taken from, and some are postal codes from Canada and other countries that don’t follow the same pattern.

In this particular case, we know what we’re looking for (postmeta with a key of wpsl_zip, and we know where it’s at (the wp_postmeta table). If you connect to the MySQL database through PHPMyAdmin or an external application you can run the following query to see how many zip codes stored have fewer than five digits:

Important: Always make a backup of your database before doing any of the changes below!

SELECT * FROM `wp_postmeta` WHERE `meta_key` = 'wpsl_zip' AND LENGTH(`meta_value`) < 5

What we’ve told the database to do, is to “select all rows from the wp_postmeta table that have a meta_key of ‘wpsl_zip’, and that have a meta_value of less than five characters in length”.

It’s important to ignore rows that already have a value of five or more characters, as LPAD will trim them to fit five characters otherwise. We don’t want that, just the ones that are too short.

The above will return all of the rows that match the query, so that we can review them and confirm that they are indeed the addresses that we want to update.

Now that we’ve identified how many there are (89 in this case), the following MySQL command will update those zipcodes using LPAD to add a left padding of 0’s until the meta_value is five characters. Values that are already five characters or larger are ignored.

UPDATE `wp_postmeta` SET `meta_value` = LPAD(`meta_value`, 5, 0) WHERE `meta_key` = 'wpsl_zip' AND LENGTH(`meta_value`) < 5

You’ll see that the WHERE clause is the same, since we already confirmed that we had the right records to change before. What we’ve done differently with this query is to say that we want to make updates to the wp_postmeta table by setting the meta_value of the rows that we selected to have exactly five characters, and that if they have fewer than five characters, to left pad them with 0’s.

Summary

To review, the MySQL function LPAD works like this:

LPAD( "cell that we want to change", "final cell string length", "what to use to left pad the cell if needed" )

I hope that helps save you spending the same time that it took me to find the problem that I had and to come up with a solution!