Diagnosing a WP eCommerce Error on GoDaddy Hosting with PHP APC

Recently there were a flurry of bug reports about a fatal error in WP eCommerce in the WordPress support forum. Initially all of the reports were from sites using GoDaddy for hosting. The common cause for the bug reports was a fatal PHP error that looks something like this:

Fatal error: WPSC_Countries::get_countries(): The script tried to execute a method or access a property of an incomplete object. Please ensure that the class definition "WPSC_Data_Map" of the object you are trying to operate on was loaded _before_ unserialize() gets called or provide a __autoload() function to load the class definition in /home/content/p3nexnas05_data03/62/2100362/html/wp-content/plugins/wp-e-commerce/wpsc-includes/wpsc-countries.class.php on line 462
Fatal error: WPSC_Countries::_dirty(): The script tried to execute a method or access a property of an incomplete object. Please ensure that the class definition "WPSC_Data_Map" of the object you are trying to operate on was loaded _before_ unserialize() gets called or provide a __autoload() function to load the class definition in /home/content/p3nexnas05_data03/62/2100362/html/wp-content/plugins/wp-e-commerce/wpsc-includes/wpsc-countries.class.php on line 1142

Justin from the WP eCommerce team, quickly figured out that if you turn off WordPress object caching the problem goes away.

The sites in question were asked to install the free WP eCommerce Site Checkup Plugin. On all of the sites checked, the plugin reported information that was helpful in getting started.

Triage of the reports told us a couple of things:

  1. Only seems to happen when APC op-code cache is being used as a WordPress Object Cache.
  2. Issue is highly intermittent
  3. Site checkup reports that APC is part of the PHP configuration
  4. Site checkup reports that WordPress doesn’t think APC is installed as an object cache
  5. Site checkup reports that WordPress doesn’t think an object cache is active.

An easy workaround for the issue is to rename the object-cache.php to something like “_object-cache.php”.  This stops the APC cache from being used as a WordPress object cache.

Because the error was only occurring in production environments, and was very intermittent stepping through in the debugger was not an option. Next best thing was the WordPress developer’s tried and tried method of using WordPress’ debug.log file, and embedding “error_log” calls at strategic places in the code to see what was going on.

We Need To Pass the Site Checkup Object Cache Test

After a couple of strategically placed logging calls showed that the object cache was only being enabled for user facing pages a read through of all of the code in object-cache.php began.  The object-cache.php was from a plugin written by WordPress Guru Mark Jaquith. Because the plugin has been around for at least 5 years, and was written by Mark, anyone would pretty much assume that the issue wasn’t inside the plugin.  But after several trips away from the code, the logging continued to point to something odd going on. Most notable, was that the object cache test in the site checkup plugin was always failing.

Finally, after a no-assumptions careful review of the APC object-cache plugin code, a test was shown to be intentionally stopping the object cache from loading on any admin request.

$oc_blocked_page = ( defined('WP_ADMIN') || defined( 'DOING_AJAX' ) || defined( 'XMLRPC_REQUEST' ) || defined( 'DOING_CRON' ) || 'wp-login.php' === basename( $_SERVER['SCRIPT_FILENAME'] ) );
if ( 'cli' !== php_sapi_name() && function_exists( 'apc_fetch' ) && !$oc_logged_in && !$oc_blocked_page ) :

Because admin requests include anything the store checkup plugin was doing, it explains why the diagnostics are failing.  It also explains why some WP eCommerce configuration options managed by the administrator in the WordPress dashboard were not being updated for the users.  Without the object cache active when the administrator does work cached values would not be refreshed. This would result in stale or invalid data being available to end users, even though it was updated for administrators. The problem would extend to include any WordPress transients that are stored into the object cache when an object cache is enabled. It would also certainly include any value manipulated by an AJAX request or a scheduled CRON.

Changing the test used to decide if the object cache should be loaded to something less specific was easy. Change the condition to check for the presence of the APC extension:

if ( extension_loaded( 'apc' ) ) :

With the APC object cache test passing, and the object cache always available we changed the symptoms of our problem.  Instead of the PHP fatal error being intermittent, it happened all of the time.  I guess that’s progress?

Why Can’t WordPress Load WP eCommerce’s Data?

Remember that the WP eCommerce plugin operates perfectly without an APC object cache and operates perfectly with a Memcached (the daemon) based object cache. But as soon as we turn on APC as an object cache we see get the fatal error.

Because the fatal error was telling us that a class definition was not loaded , the first thing was to confirm that the key classes were being included in the application.  At the top of each PHP file, prior to the class being defined, we put an error log statement to record that the file has been included.  At the top of the file that defined the WPSC_Country class the statement:

error_log( ‘including class WPSC_Country’ );

was added.  At the top of the file that defined the WPSC_Countries class the statement:

error_log( ‘including class WPSC_Countries’ );

was added. At the top of the file that defined the WPSC_Data_Map class the statement

error_log( ‘including class WPSC_Data_Map’ );

was added.  Then a click on the page refresh button in our browser, and a look into the debug.log file. This is what was there:

[12-Apr-2015 23:53:03 UTC] including class WPSC_Country [12-Apr-2015 23:53:03 UTC] including class WPSC_Countries [12-Apr-2015 23:53:03 UTC] including class WPSC_Data_Map [12-Apr-2015 23:53:03 UTC] WPSC_Countries::__construct [12-Apr-2015 23:53:03 UTC] PHP Fatal error: WPSC_Countries::new_get_countries(): The script tried to execute a method or access a property of an incomplete object. Please ensure that the class definition “WPSC_Country” of the object you are trying to operate on was loaded before unserialize() gets called or provide a __autoload() function to load the class definition in /home/content/p3pnexwpnas03_data02/88/2349788/html/wp-content/plugins/wp-e-commerce/wpsc-includes/wpsc-countries.class.php on line 484

Reading the error message it really makes little sense.  The classes are included, then PHP cant find the class definition. Puzzling.

Next experiment was to create a PHP class autoloader, the error message seems to suggest this as a solution. This was added to the plugin code:

function wpsc_class_autoload( $class ) {

   $file = strtolower( str_replace( '_', '-', $class ) );
   error_log( __FUNCTION__ . ' class is ' . $class );

   if ( file_exists( WPSC_FILE_PATH . '/wpsc-includes/' . $file . '.class.php' ) ) {
      require_once( WPSC_FILE_PATH . '/wpsc-includes/' . $file . '.class.php' );
   }
}

error_log( 'autoload register' );
spl_autoload_register( 'wpsc_class_autoload' );
Make note of the error_log call in the autoloader callback function. This should record every request for class autoloading.

Another click of the browser refresh button produced another interesting log snippet:

[13-Apr-2015 10:16:57 UTC] including class WPSC_Country
[13-Apr-2015 10:16:57 UTC] including class WPSC_Countries
[13-Apr-2015 10:16:57 UTC] autoload register
[13-Apr-2015 10:16:57 UTC] including class WPSC_Data_Map
[13-Apr-2015 10:16:57 UTC] wpsc_class_autoload class is All_in_One_SEO_Pack
[13-Apr-2015 10:16:57 UTC] wpsc_class_autoload class is Sputnik
[13-Apr-2015 10:16:57 UTC] wpsc_class_autoload class is Sputnik_Admin
[13-Apr-2015 10:16:57 UTC] wpsc_class_autoload class is Sputnik_Updater
[13-Apr-2015 10:16:57 UTC] wpsc_class_autoload class is Sputnik_Pointers
[13-Apr-2015 10:16:57 UTC] wpsc_class_autoload class is All_in_One_SEO_Pack_Module
[13-Apr-2015 10:16:57 UTC] wpsc_class_autoload class is external_links_anchor_utils
[13-Apr-2015 10:16:57 UTC] wpsc_class_autoload class is SitePress
[13-Apr-2015 10:16:57 UTC] wpsc_class_autoload class is WPML_Translation_Management
[13-Apr-2015 10:16:57 UTC] wpsc_class_autoload class is WC_Download_Handler
[13-Apr-2015 10:16:57 UTC] wpsc_class_autoload class is All_in_One_SEO_Pack_Module_Manager
[13-Apr-2015 10:16:57 UTC] wpsc_class_autoload class is All_in_One_SEO_Pack_Feature_Manager
[13-Apr-2015 10:16:57 UTC] wpsc_class_autoload class is All_in_One_SEO_Pack_Performance
[13-Apr-2015 10:16:57 UTC] WPSC_Countries::__construct
[13-Apr-2015 10:16:57 UTC] PHP Fatal error:  WPSC_Countries::get_countries(): The script tried to execute a method or access a property of an incomplete object. Please ensure that the class definition "WPSC_Country" of the object you are trying to operate on was loaded _before_ unserialize() gets called or provide a __autoload() function to load the class definition  in /home/content/p3pnexwpnas03_data02/88/2349788/html/wp-content/plugins/wp-e-commerce/wpsc-includes/wpsc-countries.class.php on line 477

Notice that many classes are recorded as looking for an autoloader, but none of the WP eCommerce classes are requested!

Something was going on where WordPress, APC or PHP was trying to parse the contents of one of our cached values. But fatally failing.

Next experiment was to try to stop APC and PHP from parsing our stored value. Easy enough to do by encoding the cached value so that it wouldn’t be seen as an object by the system code. These functions were created to save and recall the cached value.

function special_set_transient(  $transient, $value, $expiration = 0 )  {
    $value = base64_encode( serialize( $value ) );
    return set_transient( $transient, $value, $expiration );
}

function special_get_transient( $transient )  {
    $value = get_transient( $transient );
    $value = base64_decode( $value );
    $value = maybe_unserialize( $value );
    if ( empty( $value ) ) {
        $value = false;
        delete_transient( $transient );
    }

    return $value;
}

The expectation was that this would not have any effect on the issue. But, that was not the case. This is what was in the log file after many page refresh requests:

[13-Apr-2015 11:28:36 UTC] including class WPSC_Country
[13-Apr-2015 11:28:36 UTC] including class WPSC_Countries
[13-Apr-2015 11:28:36 UTC] autoload register
[13-Apr-2015 11:28:36 UTC] including class WPSC_Data_Map
[13-Apr-2015 11:28:36 UTC] wpsc_class_autoload class is All_in_One_SEO_Pack
[13-Apr-2015 11:28:36 UTC] wpsc_class_autoload class is Sputnik
[13-Apr-2015 11:28:36 UTC] wpsc_class_autoload class is Sputnik_Admin
[13-Apr-2015 11:28:36 UTC] wpsc_class_autoload class is Sputnik_Updater
[13-Apr-2015 11:28:36 UTC] wpsc_class_autoload class is Sputnik_Pointers
[13-Apr-2015 11:28:36 UTC] wpsc_class_autoload class is All_in_One_SEO_Pack_Module
[13-Apr-2015 11:28:36 UTC] wpsc_class_autoload class is external_links_anchor_utils
[13-Apr-2015 11:28:36 UTC] wpsc_class_autoload class is SitePress
[13-Apr-2015 11:28:36 UTC] wpsc_class_autoload class is WPML_Translation_Management
[13-Apr-2015 11:28:36 UTC] wpsc_class_autoload class is WC_Download_Handler
[13-Apr-2015 11:28:36 UTC] wpsc_class_autoload class is All_in_One_SEO_Pack_Module_Manager
[13-Apr-2015 11:28:36 UTC] wpsc_class_autoload class is All_in_One_SEO_Pack_Feature_Manager
[13-Apr-2015 11:28:36 UTC] wpsc_class_autoload class is All_in_One_SEO_Pack_Performance
[13-Apr-2015 11:28:36 UTC] WPSC_Countries::__construct
[13-Apr-2015 11:28:37 UTC] wpsc_class_autoload class is JQueryColorboxFrontend
[13-Apr-2015 11:28:37 UTC] wpsc_class_autoload class is Flattr
[13-Apr-2015 11:28:37 UTC] wpsc_class_autoload class is BJLL

No fatal PHP errors, not even any warnings.

Conclusions

  1. We have a fix to the object-cache.php and a potential change in WP eCommerce that will get us by the issue.
  2. The work-around that let’s WP eCommerce work in an environment that uses  APC as an object cache  seems to tell us there is an APC/PHP bug when retrieving cached objects that contain other objects from a WordPress APC object cache.

Is this a bug? Please give us your thoughts?

WP-eCommerce Tip: Hide Comments on Single Product Pages

If you have a store with hundreds of products it can be a little annoying to have to turn off comments on every product page.  But, you can add a few lines of code to a file in your mu-plugins directory, or your theme’s functions.php file.

This will turn off comments on your single product pages.

/**
 * Filter whether the current post is open for comments.
 *
 * @param bool        $open    Whether the current post is open for comments.
 * @param int|WP_Post $post_id The post ID or WP_Post object.
 */
function wpec_no_single_product_page_comments( $open, $post_id ) {
   if ( $open && is_singular() ) {
      $post_type = get_post_type( $post_id );
      if ( 'wpsc-product' == $post_type ) {
         $open = false;
      }
   }

   return $open;
}

add_filter( 'comments_open', 'wpec_no_single_product_page_comments', 10, 2 );

How to Show WP-eCommerce Products on Blog Main Page

If you are using the WP-eCommerce plugin to sell items in support of your WordPress blog you may have been wondering if it’s possible to have your products show up on your main page intermixed with your regular blog posts.

The WordPress main post “loop” can be adjusted using the pre_get_posts filter.

The filter lets you change how WordPress builds the list of posts displayed for your blog.

You can add code like what is below to a file in your mu-plugins directory or theme functions.php file.

add_action( 'pre_get_posts', 'pbci_show_products_in_loop' );

/**
 * @param WP_Query $query
 */
function pbci_show_products_in_loop( $query ) {
    if ( ! is_admin() ) {
        if ( $query->is_home() && $query->is_main_query() ) {
            $query->set( 'post_type', array( 'post', 'wpsc-product' ) );
            $query->set( 'orderby', 'modified' );
            $query->set( 'order', 'DESC' );
        }

        if ( $query->is_main_query() && $query->is_search ) {
            $query->set( 'post_type', array( 'post', 'wpsc-product' ) );
        }
    }
}


Notice the check if ( ! is_admin() ) {.  This is to be sure we don't change the post listings in the WordPress dashboard.

The check if ( $query->is_home() && $query->is_main_query() ) { tests to see if we are on the main page in the main loop.

Then $query->set( 'post_type', array( 'post', 'wpsc-product' ) ); sets the desired post types to regular posts and product posts.

If you don’t want to play with the code, but want to give this idea a try, we have put the code into a FREE PLUGIN in our store.

Customizing PayPal Checkout for WP-eCommerce

PayPal offers a really nice feature that lets you customize the look and feel of the PayPal checkout page to match the look and feel of your web site.  We highly recommend that you use this feature to have your PayPal checkout page look similar to your WP-eCommerce shopping cart pages.  It makes for a much friendlier feeling checkout experience.

But what do you do when you have one PayPal account and multiple stores.  The PayPal Payments Standard 2.0 gateway that comes with WP-eCommerce doesn’t let you override the look and feel settings on a store by store basis.  And the newer PayPal gateways that come with WP-e Commerce may not be suitable for your store for some reason.

There is an easy answer!

The PayPal gateway that comes with WP-eCommerce  has a nifty “filter” that we can use to pick any of the “styles” you have set up in your PayPal settings.  It’s only a few lines of code that you can drop into a file in the mu-plugins directory, or into your theme’s functions.php.

This little snippet of code will tell PayPal to use the ‘pyebrook’ style sheet whenever  WP-eCommerce sends a shopper to PayPal.

add_filter( 'wpsc_paypal_standard_post_data', 'my_wpsc_paypal_standard_post_data', 10 , 1 );

function my_wpsc_paypal_standard_post_data( $paypal_vars ) {
    $paypal_vars['page_style'] = 'pyebrook';
    return $paypal_vars;
}

 

And this is what your shoppers will see:

paypal-checkout-screen
Customized PayPal Checkout

 

 

 

 

 

 

 

 

 

 

Site Check Up for WP-eCommerce

When we are contacted for to help build a new WP-eCommerce site, upgrade an older WP-eCommerce installation, or fix an issue in a WP-eCommerce store there we try to gather a little technical information to understand what we are working with.

The questions we ask, and the things that we look at have been moved into a FREE, easy to use plugin that you can install to check your WP-eCommerce / WordPress configuration health.

Download the Site Check-up Plugin for WP-eCommerce here!

Checks for the following unfortunate conditions existing on your site:

  • Unreachable links to products, checkout, results and user profile pages. Checks HTTP and HTTPS.
  • Too many options in the WordPress options table
  • Too many autoload options in the WordPress options table
  • Too much autoload data in the WordPress options table
  • Too many transients in the WordPress database
  • Expired transients in the WordPress database
  • Orphaned WordPress post meta
  • Orphaned WordPress taxonomy terms
  • Memcache not present
  • APC not present
  • Object cache not functioning
  • Slow un-cached query performance
  • Slow cached query performance

Makes available to the store administrator individual actions that will:

  • Delete all WordPress Transients from the WordPress database
  • Delete expired WordPress transients from the WordPress database
  • Delete orphaned WordPress post meta
  • Delete orphaned WordPress taxonomy meta
  • Delete all files that are part of the WordPress cache
  • Flush the WordPress cache
  • Test the configuration of memcache object cache
  • Initiate a memcache (object cache) flush

WP-e-Commerce Random Cart Emptying – fix your server configuration

Using one of the less expensive hosting providers and a shared hosting plan for your WP-e-Commerce site is a great way to get started.  The hosting providers often have easy one-click setups that they have already been optimized for a WordPress blog.  These configurations can be a convenient as a starting point for setting up your WPeC site.  Not having to set up and tune your Web Server and WordPress configurations can save hours or even days worth of work.

Optimizing a server for WordPress almost always includes setting up a cache to improve the ability of your server to handle requests quickly and consistently. If you aren’t familiar with how a cache works it’s pretty simple. If the result of a computation, database request or file read might be needed later, save the result close by so that if it is needed again it both easy and fast to get.

Caching on a blog is useful because the intent is for each piece of content to be read over and over again, perhaps thousands of times. Keeping the raw data close to where the web page is created not only speeds the  experience for the end-user, it helps balance the utilization of server components.  This means more requests can be processed by less hardware and software.

About Caches

There are lots of caches that can be configured for a WordPress site.  The common types are proxy-caches, op-code caches, object (attribute-value) caching and content delivery networks (CDN).  Hosting provider’s will setup whatever a combination of cache types that matches what they anticipate to be met their users needs.

There a many implementations of each cache type some are bundled with server software, some are commercial products, some are services.  For example, there are probably hundreds of CDN that could be used with any given web site. If your web site is running on any type of Linux variant with Apache it could be the case that your hosting provider has preconfigured a server to APC for WordPress Caching.

About APC

APC offers two caching capabilities, op-code caching and attribute caching. Your site can be configured to use either APC capability, or both, or neither. It’s important to understand each cache capability, and how it helps your site.

Op-code caching stores pre-processed copies of your web site’s PHP source code so that pages will load very fast.  I benchmarked this site with APC op-code caching enabled and disabled and WordPress loaded 20 times ( 210 vs 10 milliseconds) faster with APC op-code caching enabled.  That is a huge improvement.

APC also offers attribute (object) caching.  Two things about WordPress blogs that make it a perfect fit for very active attribute caching.  First is that content is very rarely changed, it is added to.  This means that if WordPress saves an extra copy of a piece of content it doesn’t have to worry about has the value of the attribute being changed.

Second is that under the hood, WordPress data is broken into lots of distinct, small, easy to manage, pieces of data, sometimes called objects. These pieces of data used to create web pages can come from attributes and values saved in a database, or somewhere else.

Post objects have attributes with values. User objects have attributes with values. Comment also have attributes with values.  If you take a quick look at your WordPress database you will see many of these attributes and values saved in the wp_commentmeta, wp_postmeta and wp_usermeta database tables.

The core WordPress code is tuned to take advantage of attribute value (object) caching if it is available. WordPress does this by saving the attributes and their values in the object cache at the same time they are saved to, or read from, the database.

WP-e-Commerce (WPeC) is architected to take advantage of the WordPress platform and all of the performance benefits that it provides.  In WPeC products are just another WordPress post type, visitors are just another meta type, and carts are just attributes attached to visitors.

How does add to cart work?

  1. Shopper looking at a product page clicks the add to cart button,
  2. WPeC get’s the shoppers cart through the WordPress API
  3. Product is added to the shopper’s cart
  4. WPeC saves the shoppers cart through  the WordPress API

Shopper goes to checkout page and cart is empty! 🙁

What happened?

If our server configuration includes Linux, Apache using Fast CGI and APC, and is set up to use APC for attribute value caching it is likely the case that we just got hit by the behavior in this bug report.

When your web server gets a request to serve a web page or add something to a cart the web server gives the request to one of many “workers” that are available.  Each of these workers is thought to be an exact duplicate of each other. This means that any worker should be able to process any request, and the result should be the same.

But this isn’t always entirely true with regards to APC.  Each worker could have its own copy of the APC cache.

How about a demo?

We installed the apc.php statistics file that comes with the APC cache on a production web server.  Watch file cache information as we refresh the page.

Notice the hit/misses change, and they and go down.  The other stats change also.  This is because the request to serve this page is using statistics from the APC cache unique to the worker that is serving the page.

 Here is what is going on…

  1. Worker 1 gets the request to create the product page when the users cart is empty. WPeC asks WordPress to save the empty cart. A copy of the cart is put into the database and a copy gets put into worker 1’s APC cache.
  2. Worker 2 gets the request to add a product to the shoppers cart.  WPeC asks WordPress for the shopper’s cart. WordPress checks the APC cache first, it’s not there. WordPress gives WPeC the cart that is stored in the database.
  3. Worker 1 gets the request to show the checkout page. WPeC asks WordPress for the shopper’s cart. WordPress checks the APC cache first, finds the cart. But the cart is the original (empty) cart.
  4. WPeC tells the user nothing is in the cart.

What to do?

Easy.  Don’t use APC for object ( attribute-value ) caching with WordPress.  Use APC for op-code caching only.

Can object caching be turned off?

Yes.  But it’s not a good idea.  Without an object cache your site will slow down. The impact on user experience will be noticeable. However, If you want to  you can turn off object caching entirely rename or delete the object-cache.php file in your wp_content directory.

Can I fix the APC configuration?

Perhaps.  This is an article that describes what you have to do.  Not for uninitiated or the faint of heart 😉

Use a different object cache (the best  solution)

If your host is sophisticated enough to try to make APC available to you it’s also very likely that your host has memcached available.  If so, you can switch to using memcache as your object cache by replacing the object-cache.php in your wp_content directory with an object-cache.php that sends the request to memcache rather than APC.  You might want to take a look at this plugin that includes the object-cache.php you need and some installation instructions. If your host hasn’t made memcached available it’s requires some basic Linux skills to set up. Just make sure you host has given you the required permissions.

Is there an easy way to see if a site has this problem?

If you want to see if your site has this configuration problem you could also try our Snappy WPeC plugin that does provides some WPeC and WordPress diagnostic information.  The plugin is free.

If you find the snappy plugin helpful and want to tell us how much you like it, why not purchase one of our other WPeC plugins.  Perhaps the Shopper Watch plugin that let’s you see what users are looking at, and what they have in their carts, or maybe our stamps.com plugin that let’s you print postage from the WPeC sales log page.

If you need some help diagnosing and fixing up your WordPress + WPeC configuration email us and we can work with you and your hosting provider to get things set up correctly.

 

snappy-site snappy

 

Removing Fancy Notification Continue Shipping Link

If your WP-e-Commerce store has only one product you may not want the continue shopping link to display in the fancy notifications box.  This little plugin removes the link.

Inspired by this discussion

no-continue-shopping-link

 

Plugin works by processing the WPeC Filter wpsc_add_to_cart_json_response and adjusting the HTML sent to the browser after a shopper adds something to their cart.

History of WP-e-Commerce Customer/Visitor Profiles

As WPeC has grown over the years the visitor profile mechanism has evolved. This is my best recollection of the progression.

What are customer or visitor profiles?

It’s where the web site stores things like what items are in your cart, what categories you have selected to view, and anything else the site needs to remember about a shopper as they progress through your e-commerce site.

In the olden days..

Prior to sometime around WPeC release 3.8.9 (or even earlier ?) visitor profiles were stored using data connected to PHP sessions. This means that the customer data was essentially a cookie. This approach, although widely used has some drawbacks. Most notably, PHP sessions don’t work the same everywhere and they are being discontinued.

WPeC stopped using PHP sessions

Sometime around release 3.8.10(?) using sessions was discontinued and the information that connected a visitor to their profile data was put into a cookie.  The PHP session dependency was eliminated and WPeC put the identifier that connected a visitor to their profile information into a cookie.  This replicates the process used by WordPress to connect a user to their user profile.  It’s very secure and has none of the issues related to how a web site is handling PHP sessions.

What’s in the WPeC visitor ID cookie?

Same type of content that WordPress puts in the cookie it sets when a user logs in to a WordPress site. Just a randomly generated number and a magic string that only the specific server that created it knows how to validate.  This means that there in’t any useful personally identifiable or information that can be stolen from the cookie. And stealing the cookie doesn’t help someone spoof another user.

So where is the data that is connected to the visitor id cookie stored?

Until around WPeC 3.8.12(?) the visitor profile was stored in a WPeC general meta data table.  Functionally this worked really well and made WPeC a very secure commerce platform.

Upsides to storing the data in the database:

  • Private data is being protected very well, unlike trying to encrypt it and store it in a cookie where it could be stolen and hacked.
  • Web page delivery is a little smaller and quicker because there isn’t a big blob of hidden data being sent with every page view and background (AJAX) request.

There is a downside to this method…

  • The downside to this is every page view would have to get the visitor’s data from the meta table, and perhaps update it, on every page view.

WPeC team started looking to improve performance…

The discussions of the best way to improve the performance of the WPeC visitor meta are still available on GitHub and can be reviewed if anyone is interested.   But here is our summary: Three possible solutions we identified

  • Implement a caching mechanism for the WPeC meta table being used to store visitor and other information
  • Use WordPress to store visitor profile information in an existing data type get the benefits of WordPress’ built in data management and data caching
  • Use WordPress to store visitor profile information in new data type get the benefits of WordPress’ built in data management and data caching

Which of the alternatives was selected?

The WPeC development team implemented and unit tested all three solutions! Not a small amount of work. As each solution was ready it was merged into a WPeC test build and evaluated.  My recollection of the evaluation of each potential solution is as follows

Advantages Disadvantages
Common WPeC meta table with custom caching No database changes Determining which data should be cached would be difficult Caching all data could increase memory usage Several thousand lines of special purpose code would have to be thoroughly tested and maintained
Existing WordPress data type with built-in WordPress caching WPeC visitor meta data becomes very tightly integrated with WordPress user meta data and gives a convenient complete view of a user. No database changes Caching is automatic and very robust Transitioning from anonymous visitor to registered user very quick and efficient Only a small amount of code that has to be tested and maintained WPeC visitor meta data becomes very tightly integrated with WordPress user meta data and has to play nicely
New WordPress data type with built-in WordPress caching Caching is automatic and very robust Only several hundred lines of code to test and maintain New database tables that need to be initialized and maintained. Not tightly integrated with WordPress users

 

A little not about collaborative open-source development…

Open source development isn’t a democracy, nor is it a dictatorship. The best analogy I can think of it is most like when you where a kid and you got together with all the other kids in the neighborhood to do something together.  If you decided to go fishing as a group, the kid with the most knowledge of fishing exerts more influence on where you go and how you fish. If you decide to play video games, the kid with the best console and selection of games is whose house you go to, and he exerts a little more influence on which game you play. If you want to play hockey, the kid with the pond in their yard is likely to have a little more of a say. When a new kid moves into the neighborhood, even though everyone listens to the new kid, sometimes he is a little less equal among equals. So if the group decides to go skating, but the new kid says I pretty sure the ice isn’t thick enough and we’ll end up getting wet.  Everyone in the group says that the ice is fine, we were on it yesterday. When you go skating and it turns out the ice in one spot of the pond was too thin, everybody in the group gets wet. If you’re a kid you have a few choices.  You can beat up the kid who owns the pond.  If you thought the ice was thin you can say I told you so, then you get beat up (deservedly so) . You can say as a group, that really sucked, but we aren’t going to a funeral so we’ll get over it. Let’s go over to the kids house with video games and warm up, Then smile and decide as a group that maybe next time we should measure the ice in a few more places when there is some doubt on if we are doing something dangerous.

The discussion…

Over a period of a number of days, maybe weeks, a public discussion took place on which was the best solution.

Integration testing

All the solutions where functionally very good, at PyeBrook even went as far as to try each of them on WPeC sites we manage. One site was small, having about 10 products and several hundred visitors per day.   The other somewhat large, having 130,000+ products and thousands of visitors per day.  All of the solutions worked, but WordPress user table problem was observed on one of the sites and reported back to the community.  The WordPress User problem was addressed in a change to the implementation, and it appeared to address the issue more than adequately in all known test cases.

The Common WPeC meta option was eliminated first because it had the most custom code, highest potential memory footprint, the highest maintenance burden over time, and biggest pre-release testing requirement.

The choice between the other two options seemed to boil down to:

  • It would be best to use existing WordPress data type with built-in WordPress caching because it is tightly integrated with WordPress, therefore less new code,  so it is lower risk and lower maintenance burden
  • It would be best to use new WordPress data type with built-in WordPress caching is lower risk because it is independent of all other WordPress functions even though it is more code to test and maintain.

The public discussion happened. The advocates for using the existing WordPress data type table made a really good case. They reasonably believed based on the work they did to address the reported issue, that the problem was behind them.  And that the tight integration with WordPress was an advantage. The people who advocated for the new WordPress data type with built-in WordPress caching were not convinced that the solution to the issue was adequate, but they could not create additional tests that showed the problem, nor could they sway the group that the tight integration with WordPress was a disadvantage.

The decision was made, release 3.8.13 was published…

Over the next weeks a significant number of sites started having issues, and it became obvious that the suspicions that there might be scenarios where the user flooding problem would surface turned out to be true.

Knowing what we know now back then the group would make a different choice.  Knowing what we knew then now I’m not sure we would make a different choice,

Just remember the kids playing hockey who went swimming, Not going to a funeral, went to someone house warmed up, had some hot cocoa, played some video games. Next time they go skating if they aren’t sure the will measure before they skate.

Where are we now?

In the pending 3.8.14 The visitor meta infrastructure uses an independent data type.  The API and performance have been greatly improved beyond what they were at the time of the 3.8.13 release. All we are waiting for is the last remaining issues designated for release to be finished and tested.

If you can help fix a bug, or even more importantly test any the hundreds of enhancements and fixes that are coming in the 3.8.14 release jump over to GitHub and give it a go.

Stop reading now if you don’t appreciate editorializing!!!

It’s very disappointing to read in some of the forums the posts, even though they are from a very small subset of the WPeC community that are critical of the character, commitment or intent of the WP-e-Commerce development community. The WP-e-Commerce community also includes Instinct who has committed resources (in case you self-righteous trolls don’t understand resources means money and paid personnel work time ) to make this product possible.

I wish more people would respond to the trolls or anyone who tries to make anyone in the WP-e-Commerce community ( developer, user or corporate sponsor) feel bad about their role or contribution.

Don’t fall for the switch to something else because it will be better BS.  The trolls who portend to advocate this never switch.  In any case after a serious issue like this I am reminded of one of my two favorite business anecdotes. The Thomas Watson story..

“Recently, I was asked if I was going to fire an employee who made a mistake that cost the company $600,000. No, I replied, I just spent $600,000 training him. Why would I want somebody to hire his experience?”

Well you have just paid with the stress and the headache of having to deal with the issue. Why switch now when you and the development team have learned something really important. And the benefits of those lessons are right around the corner.

If you trolls want to take your shot at me point go ahead. Point me to another e-Commerce solution that can do better than this:

  • Free
  • Can run any of my clients sites including a 150,000 product web site on a $50 per month VPS with page load times less than 2 seconds.
  • Big community of quality developers where we and our clients can find both free and paid support in any region of the world
  • Plethora of free and paid plugins.
  • Robust API so we can create custom plugins without roto-tilling the core code and having to retest the world
  • Open source so I can integrate any other solution I choose when the need arises

 

Right now, I’m going to go back and fix and test a few more issues that are in the WPeC GitHub repository.  If time allows, as the 3.8.14 release gets closer, I will try to follow-up with some information on the WPeC customer/visitor meta API and some of the really cool stuff you can do with it.

Cleaning up a local commit before pushing to GitHub

If you are doing development locally and like to make lots of commits as you code and test and test you know that pushing a branch with all those commits can sometimes m amke it hard for reviewers to understand what has changed and why.

Wouldn’t it be great if you could compress all of your smaller commits together but still preserve the comments you entered with each commit? It looks like it can be done!

Found this little tip here http://stackoverflow.com/questions/5189560/how-can-i-squash-my-last-x-commits-together-using-git.

# Reset the current branch to the commit just before the last 12:
git reset --hard HEAD~12

# HEAD@{1} is where the branch was just before the previous command.
# This command sets the state of the index to be as it would just
# after a merge from that commit:
git merge --squash HEAD@{1}

# Commit those squashed changes.  The commit message will be helpfully
# prepopulated with the commit messages of all the squashed commits:
git commit