If you write WordPress plugins and make AJAX requests, you may be familiar the dreaded Javascript error: SyntaxError: JSON Parse Error: Unrecognized token '>'
Why? Why!?!
What it means is that the response your code expected is screwed up because a plugin barfed PHP warnings into the admin-ajax.php
ventilation system.
When WP_DEBUG
is on, admin-ajax.php
responses can include junk HTML output from PHP warnings, like:
<br /> <b>Notice</b>: Undefined offset: 0 in <b>/wp-content/plugins/im-gonna-break-ur-ajax.php</b> on line <b>666</b><br /> |
The fix? Catch exceptions, then exceed expectations
The way to fix this is to wrap the jQuery.parseJSON()
function in try/catch
. That will make sure that the code doesn’t fully blow up.
try { jQuery.parseJSON( response ); } catch( exception ) { console.log( exception ); } |
That will prevent your code from breaking, but it won’t make your code work.
The cause of the code breaking is the junk HTML at the beginning on the AJAX response. So, what we want to do is:
- Check for a valid JSON response
- If the JSON is invalid, strips all characters until finding a JSON-style opening of
{"
. - Check the newly stripped string to see if that is valid JSON
- If valid, return the JSON. If not, return an error message.
Here’s the code to achieve that:
/** | |
* Parse JSON string that may contain HTML elements - requires jQuery | |
* | |
* @param {string} string JSON text to attempt to parse | |
* @returns {object} Either JSON-parsed object or object with a message key containing an error message | |
*/ | |
function maybe_parse_json( string ) { | |
var json_object; | |
// Parse valid JSON | |
try { | |
json_object = jQuery.parseJSON( string ); | |
} catch ( exception ) { | |
// The JSON didn't parse most likely because PHP warnings. | |
// We attempt to strip out all content up to the expected JSON `{"` | |
var second_try = string.replace( /((.|\n)+?){"/gm, "{\"" ); | |
try { | |
json_object = $.parseJSON( second_try ); | |
} catch ( exception ) { | |
// If it doesn't work the second time, just log the error | |
console.log( '*** \n*** \n*** Error-causing response:\n***\n***\n', string ); | |
// And return an error message. | |
json_object = { | |
message: 'JSON failed: another plugin caused a conflict with completing this request. Check your browser\'s Javascript console to view the invalid content.' | |
}; | |
} | |
} | |
return json_object; | |
} |
Let me know what you think, and please fork the Gist if you have any improvements!
You must be logged in to post a comment.