How to store billing address information from the s2member plugin

s2member logos2member, the membership plugin we use on Smart Insights, doesn’t store the billing address entered when people purchase memberships or products. I needed a way to be able to get access to that information, and here’s the solution I figured out.

Why doesn’t s2member store billing address information?

Storing cardholder data such as billing address and credit card number is not secure, and puts you in a tricky situation in terms of your site’s PCI Compliance. To avoid this, s2member just passes this information straight onto your payment gateway of choice (in our case this is PayPal) and does not store it locally. It goes without saying that you should NEVER store any credit card details in the WordPress database.

Why would you need to store billing address information from the s2member plugin?

For us, there are two reasons to have access to this information;

1) We want to be able to send billing address (not credit card details) to our CRM/marketing automation platform

We have a marketing automation platform called Office Auto Pilot which runs our email and other marketing activities. It also acts as our customer relationship management (CRM) platform. Not having a member’s address and country details in this is a pain – we’re unable to segment our communications on geographical area, which is lousy when we have members in 50 different countries paying different prices in different currencies.

2) We want our members to be able to see what they’ve purchased previously, and print invoices

s2member doesn’t currently provide any functionality for generating invoices from within WordPress, or allowing members to see what they’ve paid in the past. Relying on PayPal to send receipts to our members isn’t sufficient – many require tax invoices with a letterhead, and at present that means we have to manually create an invoice. As we grow and the volumes increase, this is taking too much time.

How do we store billing address information in the s2member plugin?

s2member comes complete with hundreds of hooks and filters which allow you to attach your custom code to its functionality. Unfortunately (and sorry for saying this s2 guys as the plugin is otherwise exceptional) the documentation is practically non-existent. So you’re left with visiting the API reference and trying to figure out what does what, where and when by trial and error.

After a lot of messing around, I discovered that the action ws_plugin__s2member_during_configure_user_registration_front_side_paid is fired just after someone submits the PayPal payment form, which of course contains the billing address fields.

In order to access this information, you must first create a MU (must-use) plugin in your WordPress installation. These are plugins that WordPress will load automatically. There’s good documentation on creating an s2member MU plugin on the s2member site, so I’ll assume you’ve gone and done that and are now ready to continue.

In order to grab the billing information from the payment form, use the following function and action:


// This function will grab the user street, city, state, country and zip billing address fields and save them as user meta.

add_action('ws_plugin__s2member_during_configure_user_registration_front_side_paid', 's2_grab_fields_from_form');
function s2_grab_fields_from_form($vars = array()) {

update_user_meta( $vars['user_id'], 'billing_street', $_POST['s2member_pro_paypal_checkout']['street'] );
update_user_meta( $vars['user_id'], 'billing_city', $_POST['s2member_pro_paypal_checkout']['city'] );
update_user_meta( $vars['user_id'], 'billing_state', $_POST['s2member_pro_paypal_checkout']['state'] );
update_user_meta( $vars['user_id'], 'billing_country', $_POST['s2member_pro_paypal_checkout']['country'] );
update_user_meta( $vars['user_id'], 'billing_zip', $_POST['s2member_pro_paypal_checkout']['zip'] );

}

Now, I put the example above to show you how the $vars parameter also contains the WordPress user_id of the person who just purchased a membership, which allows you to store this (and indeed any other information in either the $vars or $_POST arrays) as user_meta. But I stress here that just because you can, doesn’t mean you should. In my case I send the billing address information straight off to our CRM system via an API call, and do not store them locally at all. I would strongly recommend you do the same.

Hope that helps someone else save some time instead of trawling the internet for hours looking for a way of storing billing address information from s2member.

Fixing PHPStorm after an OSX Mavericks update

OSX MavericksI use PHPStorm for all my development – it’s a robust and very featured IDE that has got even better recently since version 7 was released. As such it’s the application I spend a large percentage of my working day in, and therefore typical that it’s the source of another issue with OSX Mavericks after my previous issue with Vagrant. PHPStorm simply refuses to start after a OSX Mavericks update.

So how do we go about fixing PHPStorm after an OSX Mavericks update?

The issue is that OSX Mavericks doesn’t come with Java 6 installed, which is what PHPStorm requires to run. To fix it, go here and install the official Java package for OSX. After install, PHP Storm will work again.

Hooray. Maybe now I can actually get some work done today…

Fixing Vagrant after an OSX Mavericks update

OSX MavericksBeing too eager, as I generally am, I went straight ahead and updated to OSX Mavericks when it launched yesterday, and it broke my development environment.

So how do you go about fixing Vagrant after an OSX Mavericks update?

 

Updated: 30th October – issues with starting VM on computer restart 

Updated: 5th November – changes to VirtualBox in version 4.3 

After updating to OSX Mavericks, I was getting the following error message:

There was an error while executing `VBoxManage`, a CLI used by Vagrant for controlling VirtualBox. The command and stderr is shown below.
Command: ["hostonlyif", "create"]Stderr: 0%...Progress state: NS_ERROR_FAILURE
VBoxManage: error: Failed to create the host-only adapter
VBoxManage: error: VBoxNetAdpCtl: Error while adding new interface: failed to open /dev/vboxnetctl: No such file or directory
VBoxManage: error: Details: code NS_ERROR_FAILURE (0x80004005), component HostNetworkInterface, interface IHostNetworkInterface
VBoxManage: error: Context: "int handleCreate(HandlerArg*, int, int*)" at line 68 of file VBoxManageHostonly.cpp

After trying to update VirtualBox (didn’t work), refresh Vagrant (didn’t work), review permissions on the Vagrant folders (didn’t work), I stumbled across the following command, which seemed to do the trick in fixing Vagrant after the OSX Mavericks update.

sudo /Library/StartupItems/VirtualBox/VirtualBox restart

Update: If you’re running the latest 4.3 version of Virtual box the restart command has changed – it’s now;

sudo launchctl load /Library/LaunchDaemons/org.virtualbox.startup.plist

The next ‘vagrant up’ command I ran worked, and my dev environment is back in action.

Update: If you’re still having problems with virtual machine being broken on computer restart..

I know a lot of people are having a similar problem – even if you perform a graceful shutdown of your VM before turning off your mac, on restart your VM is broken again.

Last night I uninstalled and updated VirtualBox to 4.3, did the same to Vagrant, and made sure I had the latest version of Varying Vagrant Vagrants. I then killed my existing virtual machine with ‘vagrant destroy’ which has the effect of downloading a new VM on next ‘vagrant up’. After downloading and installing everything my VM was back up and running.

I then shut down my mac, and restarted. This time a ‘vagrant up’ worked. Or at least it seemed to until I discovered that no sites on the VM responded when I tried to visit them in my brower. I logged into the VM on SSH and checked NGINX – it hadn’t started for some reason, so I restarted the service with ‘service nginx reload’, which worked.

Problem is, still no sites respond.

At present the only way I can get my VM working again after a reboot is to run:

vagrant up --provision

Adding this extra parameter forces vagrant to re-run provisioning of the box which in turn forces all services to start up from scratch. This takes longer than a normal ‘vagrant up’ but it works, so for now it seems to be the best solution!

Update: People are saying that upgrading VirtualBox to the very latest 4.3.2 version has fixed the problem

It hasn’t for me, sadly. I can now start the VM with no issues, but I can’t access any sites on it as NGINX refuses to start properly. Not a VBox problem, more an issue with something in my Varying Vagrant Vagrants config, I suspect. I’m still having to run a ‘vagrant up –provision’ to get going again after a restart.

Let me know in the comments if you’ve found a better way.

Implementing Google Universal Analytics Measurement Protocol in PHP and WordPress

Google Universal AnalyticsI’ve had some historic difficulty in being able to track ecommerce transactions in Google Analytics that happen ‘behind the scenes’ of the Smart Insights site – typically when PayPal sends an IPN message, server to server, for a subscription renewal in our case. Since those messages don’t touch the browser, you can’t use the Google Analytics javascript to track them. So I started looking to see how/if I could send data directly to Google Analytics from a backend script running on our WordPress install.

I found several custom PHP classes that seemed, initially, to do the trick;

Problem is, they’re both pretty old and seem to be no longer developed, so I figured there must be something better. My colleague Dave Chaffey then pointed me in the direction of the Google Measurement Protocol, which I hadn’t heard of before.

What is the Google Measurement Protocol and why should I care?

The Measurement Protocol is an addition to the latest version of , which is called ‘Universal Analytics’. From the explainer documentation;

The Google Analytics Measurement Protocol allows developers to make HTTP requests to send raw user interaction data directly to Google Analytics servers. This allows developers to measure how users interact with their business from almost any environment.

More at ‘‘

Google allows you to form and send any of the following types of Analytics request via this API;

  • Page Tracking
  • Event Tracking
  • Ecommerce Tracking
  • Social Interactions
  • Exception Tracking
  • User Timing Tracking
  • App tracking

Using the Google Measurement Protocol in PHP and WordPress

NOTE:  You can only use the Measurement Protocol if you have the Universal Analytics tracking code set up on your site. It will not work with the standard tracking code. If you need help with this, there’s a fantastic introduction at the KissMetrics site: Universal Analytics: Switching to the Next Version of Google Analytics

As is typical with Google and ‘beta’ products (as the Universal Analytics code is still in beta) they give pretty sparse examples and no specific code, so it’s up to you to work things out yourself.

In my case I wanted to be able to fire two types of requests to Google – an ecommerce transaction when a membership renewal occurs, and a custom pageview which is used as a ‘‘ on Analytics.

As I wanted the code to be reusable throughout the WordPress install, I came up with a set of functions (mine lives in a function file of its own, yours could live in your standard theme functions.php file if you wish).

There are two steps needed to make a request to the Measurement Protocol.

1. Obtain the current user’s unique identifier (CID) from the Google Analytics cookie (if it exists!)

Very vital, this, and something I ended up banging my head on the desk about. When a user lands on your site, the Google Analytics code assigns them a unique identifer. This lives in a cookie, and follows them across all requests they make on your site. If you fire a server side request and make up your own unique identifier, the Analytics service has no way of matching the two up.

Obviously this isn’t a problem in my original use case – a behind the scenes ecommerce renewal won’t have a browser cookie to get anything from, and it doesn’t matter that you assign it a unique identifier all of its own. But – if you decide to use the Measurement Protocol for other things, front of site (and I did within 10 minutes of finishing my first code), then you do need to check for the existence of that cookie first. If you don’t, a user that has logged page history will suddenly become anonymous when you fire your Measurement Protocol request. This means that things like conversion funnels won’t work, which is not good.

So, here’s how we parse the GA cookie;

// Handle the parsing of the _ga cookie or setting it to a unique identifier
function gaParseCookie() {
  if (isset($_COOKIE['_ga'])) {
    list($version,$domainDepth, $cid1, $cid2) = split('[\.]', $_COOKIE["_ga"],4);
    $contents = array('version' => $version, 'domainDepth' => $domainDepth, 'cid' => $cid1.'.'.$cid2);
    $cid = $contents['cid'];
  }
  else $cid = gaGenUUID();
  return $cid;
}

This code will pluck the CID value from the cookie if it exists. If not, it runs another function to generate one – gaGenUUID(). The Measurement Protocol documents say that the CID must “be a random UUID (version 4) as described in http://www.ietf.org/rfc/rfc4122.txt“. Ah, okay. So let’s create one of those, then;

// Generate UUID v4 function - needed to generate a CID when one isn't available
function gaGenUUID() {
  return sprintf( '%04x%04x-%04x-%04x-%04x-%04x%04x%04x',
    // 32 bits for "time_low"
    mt_rand( 0, 0xffff ), mt_rand( 0, 0xffff ),

    // 16 bits for "time_mid"
    mt_rand( 0, 0xffff ),

    // 16 bits for "time_hi_and_version",
    // four most significant bits holds version number 4
    mt_rand( 0, 0x0fff ) | 0x4000,

    // 16 bits, 8 bits for "clk_seq_hi_res",
    // 8 bits for "clk_seq_low",
    // two most significant bits holds zero and one for variant DCE1.1
    mt_rand( 0, 0x3fff ) | 0x8000,

    // 48 bits for "node"
    mt_rand( 0, 0xffff ), mt_rand( 0, 0xffff ), mt_rand( 0, 0xffff )
  );
}

So, we now have a CID that we can use.

2. Build and send our Measurement Protocol request

There are two functions used here – one to build the request, the other to send it. In both cases you call gaBuildHit() with two parameters – the method (which in my example is either ‘pageview’ or ‘ecommerce’) and an array of data that is needed by the Measurement Protocol. This differs depending on the method you’re using, so let’s jump into the code and I’ll explain more afterward.

function gaBuildHit( $method = null, $info = null ) {
  if ( $method && $info) {

  // Standard params
  $v = 1;
  $tid = "UA-XXXXXXX"; // Put your own Analytics ID in here
  $cid = gaParseCookie();

  // Register a PAGEVIEW
  if ($method === 'pageview') {

    // Send PageView hit
    $data = array(
      'v' => $v,
      'tid' => $tid,
      'cid' => $cid,
      't' => 'pageview',
      'dt' => $info['title'],
      'dp' => $info['slug']
    );

    gaFireHit($data);

  } // end pageview method

  // Register an ECOMMERCE TRANSACTION (and an associated ITEM)
  else if ($method === 'ecommerce') {

    // Set up Transaction params
    $ti = uniqid(); // Transaction ID
    $ta = 'SI';
    $tr = $info['price']; // transaction value (native currency)
    $cu = $info['cc']; // currency code

    // Send Transaction hit
    $data = array(
      'v' => $v,
      'tid' => $tid,
      'cid' => $cid,
      't' => 'transaction',
      'ti' => $ti,
      'ta' => $ta,
      'tr' => $tr,
      'cu' => $cu
    );
    gaFireHit($data);

    // Set up Item params
    $in = urlencode($info['info']->product_name); // item name;
    $ip = $tr;
    $iq = 1;
    $ic = urlencode($info['info']->product_id); // item SKU
    $iv = urlencode('SI'); // Product Category - we use 'SI' in all cases, you may not want to

    // Send Item hit
    $data = array(
      'v' => $v,
      'tid' => $tid,
      'cid' => $cid,
      't' => 'item',
      'ti' => $ti,
      'in' => $in,
      'ip' => $ip,
      'iq' => $iq,
      'ic' => $ic,
      'iv' => $iv,
      'cu' => $cu
    );
    gaFireHit($data);

  } // end ecommerce method
 }
}

// See https://developers.google.com/analytics/devguides/collection/protocol/v1/devguide
function gaFireHit( $data = null ) {
  if ( $data ) {
    $getString = 'https://ssl.google-analytics.com/collect';
    $getString .= '?payload_data&';
    $getString .= http_build_query($data);
    $result = wp_remote_get( $getString );

    #$sendlog = error_log($getString, 1, ""); // comment this in and change your email to get an log sent to your email

    return $result;
  }
  return false;
}

Registering a pageview

Details on the parameters needed .

You need to send the code in the following way:

$data = array(
  'title' => 'Any page title you want to send',
  'slug' => '/please/change/me/to-whatever-you-want/'
);
gaBuildHit( 'pageview', $data);

Registering an ecommerce transaction

You have to send a minimum of two requests here – the first is the initial transaction, and the second is for the specific item, They’re bound together on the same ‘transaction ID’ so Analytics can match them up. Details on the parameters needed .

Please note – if you have multiple line items, my code doesn’t accommodate that as we only ever have one. You’ll need to amend the code to loop over the items and send them all.

You need to send the code in the following way:

$data = array(
  'info' => array ('product_id' => 102, 'product_name' => 'Smart Insights membership' ), // we already have these details in an array so send that, you may want to amend
  'cc' => 'GBP', // the currency code
  'price' => 209.00, // the price
  'country' => GB // the country ISO code
);
gaBuildHit( 'ecommerce', $data);

Some things to be aware of

  1. If you choose to take a peek at what is returned from the API after a request, you’ll be surprised to learn that you only ever get a 200 response, regardless whether your request has succeeded or failed. So it’s a bit pointless, really, you can’t debug it that way
  2. If you use the Real Time view on Analytics, you will be able to see your ‘pageview’ requests appear within seconds, so you know it works!
  3. If you use the ‘ecommerce’ method, you’ll probably have to wait for 2-3 hours (like I did) before data appears, or not. Not helpful, but the code should work – at least you don’t have to start from scratch like I did! 🙂
  4. The code above is written for our site – you will more than likely have to tweak and change it to make it work for yours.

And that’s that – though it could do with some tidying (which I’ll do when I extend it further), it should be easy to add any of the other methods available on the Measurement Protocol API to these functions. Running within your WordPress install it should give a good starting point to using the server side Google Analytics Measurement Protocol in PHP and WordPress.

I’d love to hear how other WordPress developers are using the new Google Universal Analytics Measurement Protocol within their WordPress sites – let me know in the comments!

How to monitor and reduce WordPress memory usage by plugins

WordPress memory

One of the best things about WordPress is that it’s so easy to extend your site’s functionality with the many (mostly) free plugins available on the plugin repository. But loading your site with too many plugins can cause your site to consume too many resources on your server, slowing your site down. So how do you find out what resources your plugins are consuming to help you reduce WordPress memory usage and speed up your site?

Reduce WordPress memory usage by plugins

In a WordPress page request, the point at which plugins are loaded depends on how they’ve been coded. WordPress runs through a series of typical actions on every request. You can see these actions here, including the order in which they are run. A plugin developer decided where in this their plugin is needed, depending on the functionality the plugin offers, and ‘hooks’ into one of these actions, overiding or extending the default WordPress functionality with their custom code. More general information on the basics of plugin writing is available at the WordPress Codex.

So, as an example you’ve got a site that has 10 (or more!) plugins. These are firing at different times during a page request, hooking into different actions, all over the place. So how do you go about monitoring which plugins are most intensive?

As standard, there isn’t an easy way to monitor what WordPress memory usage is as it loads all of the plugins you’ve got installed on your site. But there are three plugins that in tandem, can really help you to find out what’s causing your site to slow down. Let’s look at them.

1) P3 (Plugin Performance Profiler)

Created by the in-house team at GoDaddy, the P3 (Plugin Performance Profiler) plugin allows you to run a scan over your site to determine what resources your plugins are using, and when, during a standard page request. This allows you to see the worst offenders and reduce WordPress memory usage by removing them or finding alternatives.

Once you’ve installed the plugin running a scan is easy and quick, even on a large site. Once the scan is complete you’ll see a comprehensive results report such as this;

P3 (Plugin Performance Profiler) Report
P3 (Plugin Performance Profiler) Report

The Runtime by Plugin report shows you a simple pie breakdown of which plugins are causing the most load on your site during a page request. Very useful, and a very quick way for you to identify and reduce WordPress memory usage by removing plugins that you don’t need.

Even more useful is the Detailed Timeline, which shows when the plugins are being loaded during the page request, so you can see if any particular one is causing a problem at a particular point.

Detailed Timeline of plugin load
Detailed Timeline of plugin load

Using the P3 (Plugin Performance Profiler) is a great start, but how do we get more information about what’s causing our site to slow down?

2) Memory Viewer

As the developer of the Memory Viewer plugin says;

Memory Viewer is a WordPress plugin that allows you to view WordPress’ memory utilization at several hooks during WordPress’ execution. It also shows a summary of MySQL Queries that have ran as well as CPU time.

Once installed, administrative users will see a new panel at the bottom of every page;

Memory Monitor output
Memory Monitor output

The report shows the memory usage at every major action hook, along with statistics on time and MySQL usage. You can also choose to show the queries that are happening at each hook, and output allows gives you an idea as to what code is responsible, which allows you to pinpoint exactly which ones are causing excessive load.

Generally a good indicator is when you see the ‘Current Memory Usage’ column leap up significantly from one action to the next. Any large jumps are worthy of investigation, as there could be plugins running that are the cause, or custom scripts in your theme that need optimisation. By removing or optimising these blockages, you can reduce WordPress memory usage significantly and then retest to see the effect of your changes on page load speed.

3) Debug Bar

Finally, the Debug Bar plugin offers similar functionality to Memory Monitor, but installs a panel into the WordPress admin bar. It is also extendable via other plugins to track and monitor other data such as the errors and warnings that PHP may record when you have the WordPress debug, WP_DEBUG, switched on.

Personally I prefere the ease and simplicity of Memory Monitor, but there’s no doubt that Debug Bar is extremely powerful.

Debug Bar output
Debug Bar output

So that’s three different, easy ways to monitor your WordPress site and find out which plugins and scripts you need to consider removing or tweaking to reduce WordPress memory usage and speed up your site.

I’d be really interested to hear what other WordPress developers use to monitor and optimise their sites.

Increasing the PHP timeout on NGINX for WordPress

wordpress-nginxI’ve been using a Vagrant development set up for a while now, which has introduced me to NGINX after always using Apache in the past. The transition has been fine in the main, though I had an issue yesterday with PHP scripts timing out on me, so needed to figure out how to extend the script execution time.

I’ve started using the excellent WP Migrate DB plugin to synch my local development environment database with the live staging server. It’s well worth spending $19 on the Pro version, by the way – it offers a lot of extra features for the small outlay.

The plugin works by you installing it on both your local and staging sites, and then authorising them to ‘see’ each other using private API keys – it’ll then push (or pull) and overwrite the database from whichever site you choose.

The problem I experienced was that the Smart Insights database is pretty large by WordPress standards – a good couple of hundred MB, and when attempting to pull this down to my local development environment I kept getting “504 Gateway Time-out” errors. Guessing it was more than likely a local timeout issue, I looked around on increasing the PHP timeout on NGINX for WordPress.

Depending on how you’re using NGINX, the answer is that you may have to change a few different things.

NB: I’m using Jeremy Felt’s ‘Varying Vagrant Vagrants’ setup here, so the instructions are specific to that, though I’ll include the default locations too.

Increasing the PHP timeout in the php.ini file

If using ‘Varying Vagrant Vagrants’;

  1. Open your vagrant-local folder root
  2. Open config/php5-fpm-config/php.ini
  3. Change the following line to the length of time you want (in seconds)
max_execution_time = 500

If using a standard server setup the instructions are the same, but the path will generally be /etc/php5/fpm/php.ini.

Increasing the PHP timeout in PHP-FPM

If using ‘Varying Vagrant Vagrants’ without changes, you don’t need this step, but best to check;

  1. Open your vagrant-local folder root
  2. Open config/php5-fpm-config/www.conf
  3. Change/add the following line to the length of time you want (in seconds)
request_terminate_timeout = 500

If using a standard server setup the instructions are the same, but the path will generally be /etc/php5/fpm/pool.d/www.conf.

Increasing the PHP timeout on NGINX config

If using ‘Varying Vagrant Vagrants’ without changes, you shouldn’t need this step either;

  1. Open your vagrant-local folder root
  2. Open config/nginx-config/nginx.conf
  3. Change/add the following line inside the existing http{} section, to the length of time you want (in seconds)
http {
#...
fastcgi_read_timeout 500;
#...
}

If using a standard server setup the instructions are the same, but the path will generally be /etc/nginx/nginx.conf.

Restarting PHP and NGINX

Don’t forget to restart both PHP and NGINX so your changes take affect! You can do this on the command line with the following;

service php5-fpm reload
service nginx reload

After restarting, WP Migrate DB successfully migrated the database from the live staging server to my local copy – way easier than manually exporting/tranferring/importing databases manually!

Hope that helps someone save a bit of time – I’d be interested in knowing what other people think of NGINX in comparison to Apache – let me know!

Code snippet – strip links from string in PHP

Ever wanted to quickly and easily strip links from a string in PHP, but don’t want to use strip_tags because it forces you to manually specify every tag you want to keep, and not letting you tell it which ones to strip?

The other day while doing some PHP development I had an issue with a custom WordPress template that was shortening a string to 100 characters on output. The HTML of the page was broken, which was causing content within a jQuery tab to not display.

I couldn’t figure out why at first. And then I realised that the shortened version ended before the link HTML was completed, which caused the browser to see it as a half closed tag and break.

Thankfully there’s a simple solution by way of a regular expression;

$string = "I am a lot of text with <a href="#">links in it"</a>";
$result = preg_replace('/<a href=\"(.*?)\">(.*?)<\/a>/', "\\2", $string);
echo $result; // this will output "I am a lot of text with links in it"

Hope that helps someone else out.