The first bug that was reported for Genesis 2.0 can serve as a learning opportunity for lots of developers to understand a little more about Genesis. It’s about a bug caused by a type hint.
What’s Affected
Typically tends to be old themes that include a colour or style selector, and have been updated since Genesis 1.7 (July 2011), when the Sanitization class was introduced, but maybe not since Genesis 1.8, when the style selector setting was then added to Genesis itself.
Child themes thought to be affected include Associate, Copyblogger, Generate and News. If you know of another one, please let me know in the comments below.
However, it’s really any theme or plugin which is calling the genesis_add_option_filter()
with a string as the third argument.
The Problem
While the front-end of the site is still accessible, updating to Genesis 2.0 will result in the admin dashboard giving out a fatal error like:
Catchable fatal error: Argument 3 passed to Genesis_Settings_Sanitizer::add_filter() must be an array, string given, called in .../wp-content/themes/genesis/lib/classes/sanitization.php on line 287 and defined in .../wp-content/themes/genesis/lib/classes/sanitization.php on line 69
If you have WP_DEBUG
set to false, or otherwise have error messages disabled in PHP, then you may just see a white screen.
The Bug
One of the improvements Genesis 2.0 made was to add type hints where possible. Here’s my explanation about the this change from my Changes in Genesis 2.0 book:
Type hinting means functions are able to force parameters to be a certain type. If the parameter is a different type, then a catchable fatal error occurs, the benefit being that unexpected data shows up easier than trying to work through some incorrect logic. The other benefit is that code editors can use the type hint information – it might help with writing the
@param
type for DocBlocks, or it might help with autocomplete of variables or properties within the function or method itself.While lots of functions within Genesis accept arrays, not all of them can be type hinted. Methods with the same name in classes that are extended from WordPress class can’t have them (since the type hint is not on the original method, and the signatures must match), nor can methods which accept array or strings arguments.
In this case, we need to look at the functions to see what is going on. Line 287 of lib/classes/sanitization.php
refers to:
<?php | |
/** | |
* Registers an option sanitization filter. | |
* | |
* If the option is an "array" option type with "suboptions", you have to use the third param to specify the | |
* suboption or suboptions you want the filter to apply to. DO NOT call this without the third parameter on an option | |
* that is an array option, because in that case it will apply that filter to the array(), not each member. | |
* | |
* Use the 'genesis_settings_sanitizer_init' action to be notified when this function is safe to use | |
* | |
* @since 1.7.0 | |
* | |
* @uses Genesis_Settings_Sanitizer::add_filter() | |
* | |
* @param string $filter The filter to call (see Genesis_Settings_Sanitizer::$available_filters for options) | |
* @param string $option The WordPress option name | |
* @param string|array $suboption Optional. The suboption or suboptions you want to filter | |
* | |
* @return true | |
*/ | |
function genesis_add_option_filter( $filter, $option, $suboption = null ) { | |
return Genesis_Settings_Sanitizer::$instance->add_filter( $filter, $option, $suboption ); | |
} |
This is fairly simple – the genesis_add_option_filter()
is a wrapper for an add_filter()
method in the Genesis_Settings_Sanitizer
class, and the parameters are passed directly through. Note that their is no type hint (correct) for the suboption
parameter, since the documentation for it says that it can accept a string or an array.
Line 69 refers to the add_filter()
method:
<?php | |
/** | |
* Add sanitization filters to options. | |
* | |
* Associates a sanitization filter to each option (or sub options if they | |
* exist) before adding a reference to run the option through that | |
* sanitizer at the right time. | |
* | |
* @since 1.7.0 | |
* | |
* @param string $filter Sanitization filter type | |
* @param string $option Option key | |
* @param array $suboption Optional. Suboption key | |
* @return boolean Returns true when complete | |
*/ | |
function add_filter( $filter, $option, array $suboption = null ) { | |
if ( is_array( $suboption ) ) { | |
foreach ( $suboption as $so ) { | |
$this->options[$option][$so] = $filter; | |
} | |
} elseif ( is_null( $suboption ) ) { | |
$this->options[$option] = $filter; | |
} else { | |
$this->options[$option][$suboption] = $filter; | |
} | |
add_filter( 'sanitize_option_' . $option, array( $this, 'sanitize' ), 10, 2 ); | |
return true; | |
} |
It’s not important to understand how this method works, but it basically tells a setting to pass through a sanitizing filter before it is saved. For instance, for checkboxes, it should pass through the one_zero
filter, which means that if the value is not a 1
or a 0
, it is rejected and not saved.
You’ll notice that there’s an array
type hint on the third parameter. Yet the body of the function checks that $suboption
to see if it’s an array, but also handles the case when it isn’t! That means that while strings are handled perfectly fine within the function, the presence of a type hint means that PHP doesn’t let any strings get that far.
When I created the pull request in January 2013 that added type hints, I went through the project and looked for the string “@param array”, and this was one of the results. So yes, the bug is my fault (sorry!). In this case, the documentation was wrong. To make matters worse, the incorrect documentation was added in September 2011 by … me.
The Fix
There are several ways of fixing the problem so that the admin dashboard comes back, but the method I strongly recommend is below. I’ve heard that the StudioPress Support team are suggesting other methods from just stopping the style selector code from running, to replacing it with data to enable the one built-in to Genesis. My opinion is that the less non-developers have to do with fixing code, the better, but each to their own.
Remove The Type Hint
Since that type hint is the cause of the bug, we can just remove it. We’ll be editing Genesis core files, which is usually a big no-no, but since this amendment has already been made to Genesis development code, you can be sure that the fix will be persisted once the next version of Genesis is released.
- Open up
genesis/lib/classes/sanitization.php
at line 69. - Change:
function add_filter( $filter, $option, array $suboption = null ) {
to
function add_filter( $filter, $option, $suboption = null ) {
- Save and upload to your website. Refresh your admin page, and it should all be working again.
The advantage of doing this method over the others is that:
- It’s the removal of 6 characters – not too tricky.
- It fixes the cause of the problem, and not the symptoms.
- Doing this fix once means that all of your themes (perhaps on a multisite) don’t need fixing individually.
- It will also fix it for any active plugins that call
genesis_add_option_filter()
as well. - It’s the same fix, for whatever theme you’re using, unlike the theme-specific style selector code.
- The next version of Genesis applies the same fix.
Final Words
The bug itself is relatively small, and only known to affect a limited number of cases – those running old versions of the affected child themes for instance. Even so, it can be frustrating if you’re one of the ones affected, so follow the instructions above and get back into your site.
Gary, so interested to see this because one of my sites has encountered a similar error, although it is a different one. The support team asked me to delete a line calling style.php from my functions file but since that line wasn’t in there, it didn’t help. Still trying to resolve the issue, actually. I’m going to look a little more since it seems like the cases are similar.
The “delete the style.php” line is one of the suggestions the support team is making, which actually then wipes out the style selector (not helpful if you’re using a non-default color scheme!). If you find out what the problem was, I’d love to know.
Well, based on your post, I dug into the files the error referenced, which suggested that something funky was going on with the $defaults set up by the functions file for the background image (Stretch theme). I commented out the section setting that up and the Live Preview for the theme is working again (I deactivated the theme because I didn’t want to deal with it, but the LP was still throwing the same error–now it’s not). I can email you all the details if you want but I hadn’t changed much of anything in that file so the original should have the same issue, is my guess. I sent a message to the team saying all this, too, so hopefully they’ll sort it out.
Hi Gary,
I had this problem twice this morning (haven’t checked all the sites I maintain jet. They are both based on Associate childtheme.
Regards
Karin
Thanks. I’ve updated the post to include Associate as one of the child themes affected.
How about installing the Genesis Beta Tester plugin and updating to the latest version rather than editing the Genesis file?
Because the beta version of 2.0.1 doesn’t exist (and may not ever exist), so folks will be left waiting until 2.0.1 final comes out.
Hi!
Thank you so much for your recommendation. Unfortunately, it did not help me. I am still having problems with the white screen of death.
I am using the education theme. Is there anything there I should change as well?
Thanks,
Erik
Erik,
If you’ve updated to Genesis 2.0.1 and still having problems, then you’ll need to give StudioPress support a shout. They’ll probably tell you to go in to your site via FTP and temporarily rename the plugin and education directories and then reloading the site to see if you can log in. Once there, visit the plugins page (you’ll get a load of red warnings saying that plugins got disabled) and maybe the Appearance-> Themes page to ensure Education got disabled. Then you rename the plugin and child theme folder back to where you started, and see if everything is still fine. After that, enable each plugin in turn and check to see if it’s still fine after each one. If all of them are fine, activate the child theme. If still fine, then you’re OK, if not, get back in by doing the same steps again, and check the child theme files for an issue.