This update has been almost six weeks in the works. Granted, much of that time has been spent doing my “day job” work, but it has still taken a much longer time than I wanted  — especially considering that it’s a bug fix upgrade. During that time, I issued two public betas (4.0.4b1 and 4.0.4b2), which did not solve the core problem (which I’ll get to in a minute). They did, however, make it abundantly clear that the existing payment gateway architecture was simply not acceptable.

The problem: round-tripping to PayPal

The problem was a set of intermittent reports. Users… sometimes… weren’t properly getting donor address information stored in the database after a donation. I, of course, didn’t have the problem. For me, it worked just fine. As a result, I wasn’t able to repeat the problem. I requested some databases and logs, and I’m very grateful for the users who provided them.

Eventually, I hit on what I thought was going on: transactions that were initiated weren’t properly recording data when they came back from PayPal. As it turned out, there were a bunch of related gotchas built into the way the original Seamless Donations handled this process, and which I migrated along into the 4.0 release.

First, Seamless Donations used WordPress transients to store transaction data before jumping from the form to PayPal. Transient data, while it’s supposed to live for a while, has been known to be flushed early on hosts strapped for resources. Often, when Seamless Donations returned from PayPal, that data was gone. I thought that was the only problem, so  I fixed it, released a beta and thought we were done.

Not so much. There were still problems, more intermittent, because the transient fix helped somewhat. I eventually figured out that the round-trip process worked perfectly in Chrome, but not in Firefox. A couple of weekends and a prodigious amount of profanity later, and I discovered it was JavaScript. Apparently, JavaScript wasn’t properly “bubbling” up some signals, and so the Ajax process wasn’t launching reliably, causing no end of hassle.

I spent a lot of time on this, reengineering the JavaScript a couple of different times, rewriting the entire cart sequence, undoing and recoding a ton of jQuery, only to find more and more quirks in the JavaScript.

Finally, I decided to ditch the whole payment architecture and start over.

From JavaScript to PHP

Seamless Donations was built to capture form data using jQuery and JavaScript and then — still in JavaScript — connect to PayPal, send in the payment data, and wait for a response message that confirmed the payment. This, not to put too fine a point on it, is insanity.

We were relying on code running in the browser to contact PayPal and make the payment. Of course, we had no idea what browser would be hitting a donation site, but it was up to the browser to do all the heavy lifting. Any glitch whatsoever in how the browser processed the payment code and everything went to crap.

As I mentioned above, Seamless Donations was also counting on transient data to store transaction information. “Transient” and “transaction” are two concepts not meant to go together. My first step was to add a new table to WordPress: wp_seamless_donations_audit. This provides an ultimate audit path, containing all of the information entered by the user on the form, tied to a unique transaction ID. Now, instead of coming back to your Web site and just hoping that your transient hasn’t been blasted away by some housekeeping process, your data is solid and secure in its own table.

Next, instead of using JavaScript to make the call into PayPal (and thereby run in the client browser), I rewrote the code to run in PHP (and thereby run on your server, where it belongs). This took a bit of work to figure out because PayPal’s published PHP interface is for REST, which is fine, but requires a library called cURL. While most hosts have cURL, not all do, and I wanted the core of Seamless Donations to require no more prerequisites than WordPress itself.

Eventually, though, I rewrote the code using HTTP POST protocol, and it properly round-trips to PayPal and records the data. I tested it on Mac, on Safari, Chrome, and Firefox, and on Windows with Chrome, Firefox and IE. I haven’t yet tested with Windows 10’s Edge, but if it works in Firefox and IE, it should work in Edge.

There is a new file, seamless-donations-payment.php, which contains the now-PHP-based PayPal payment gateway. The form action points to seamless-donations-payment.php and onSubmit points to the form validation JavaScript. The form JavaScript no longer transitions to payment. Either the entered form data validates or it doesn’t validate. The idea was to remove Ajax completely from the PayPal payment submit sequence.

New 4.0.5 beta released

This post corresponds with the release of a 4.0.5 beta. 4.0.5 will not go up on the repository. Instead, this new version will live until we get some feedback as to whether it’s solid (or causes its own problems). When it passes testing, the official next release will be 4.0.6

Thanks to everyone for your help and patience.