• Skip to primary navigation
  • Skip to main content
  • Skip to primary sidebar

My Monkey Do

A Log of Coding Solutions

  • Home
  • Web Hosts
  • Tools
  • About

eCommerce

PCI Compliance

February 13, 2015 by Webhead

Fill out the SAQ-EP if you are a normal self hosted ecommerce site that outsources their payment to a 3rd party.  Self Assessment Questionnaire (SAQ).

http://www.pci-initiative.org/content/saq-ep-partially-outsourced-e-commerce-merchants

SAQ A vs. A-EP: What E-Commerce Merchants, Service Providers Need to Know Now

Worth noting that others may interpret this differently:

http://stackoverflow.com/questions/21484714/is-pci-saq-a-sufficient-for-an-ecommerce-website-with-a-custom-payment-page

https://pcissc.secure.force.com/faq/articles/Frequently_Asked_Question/Why-is-SAQ-A-EP-used-for-Direct-Post-while-SAQ-A-is-used-for-iFrame-or-URL-redirect

Just fyi (shameless affiliate link coming up), WPEngine host is PCI Compliant “as long as no payment card data is stored, hosted, or otherwise processed by WP Engine…”

Filed Under: Server Stuff Tagged With: eCommerce

Google Analytics Measurement Protocol for Subscriptions

January 11, 2014 by Webhead

Send Analytics Data Directly From Your Server

Google Analytics Measurement Protocol is available for Google’s Universal Analytics.  It was released in the first part of 2013 and is as of this writing still in public beta.  It allows developers to make HTTP requests to send raw data directly to Google Analytics.

Subscription Renewals for eCommerce Sites

I found and used the Measurement Protocol specifically to solve a problem with tracking subscription renewals.  I was using WooCommerce and the Subscription extension as my eCommerce subscription site and found a couple things not working for me when I was using the built-in Analytics eCommerce tracking.

For one, I had Universal Analytics but WooCommerce was using the legacy ga.js analytics.  So nothing was being tracked.

Secondly, the WooCommerce code to track purchases was done on the Thank You page.  While this is fine for normal purchases, I wanted to track renewals via the wp cron jobs also.

How to Use Google Measurement Protocol in WordPress and WooCommerce

First, let me say at the time of this writing there are very little examples on implementing the code.  While Google’s documentation is great, I still had questions.  This post on using the measurement protocol from Stu Miller got me started and almost completed the work for me.  I am in no way an expert at WooCommerce or Subscriptions so I didn’t want to put this code into a plugin.  Also, WooCommerce may soon update their analytics plugin making this code obsolete.

1. The CID – The Client Id

The most confusing thing about the Measurement Protocol is how to link up the user to Google’s “anonymous” user.  As of this writing Google is intending to have a user ID field, but it is not yet available.  From the google groups forum and the documentation, the CID field should be either a UUID Version 4 or their legacy anonymous identifier format “X.Y” where each are 32-bit random numbers.  The X and Y are actually the Google assigned random id and the timestamp which the id was assigned as noted in this stackoverflow post.

So to link a Google Analytics user with your user/subscriber you would need to parse the “_ga” cookie and save the id.timestamp portion like I do in my_ga_parse_user() and my_setup_new_user().

2. The Renewal Order (WooCommerce)

The second most confusing thing (for me anyway) was recording the correct order.  In WooCommerce every subscription renewal creates a new order.  In my case the original order is a 7 day free trial and then $10 every month after that.  So the original order’s total price along with the transaction is $0.  The renewal order should be $10, but analytics was not recording it.  The reason is that when a renewal order is created almost all of the original orders postmeta data is copied into the renewal order.  This means that _ga_tracked is also copied. In my_ga_track_payment() the _ga_tracked postemeta is checked first to make sure an order isn’t recorded more than once.  If this is copied to the renewal order the renewal order will never get tracked.  The function hooked to the  woocommerce_subscriptions_renewal_order_meta_query filter solved this problem.

3. Debugging

I had a tough time trying things out in subscriptions because a renewal order is created once a day at most.  To get around this I created my_ga_debug_next_payment() to speed up the payment process.  This method sets the next payment date to 5 minutes from the current time.  I was using the Stripe payment gateway so I’m not sure if this will work for PayPal or any other gateways.

Here’s the Code

<?php
/**
* See https://groups.google.com/forum/#!msg/google-analytics-measurement-protocol/rE9otWYDFHw/8JlJJV-UmKcJ
* a person from Google says cid should be X.Y format.
* and https://developers.google.com/analytics/devguides/collection/protocol/v1/devguide
* Apparently whether hit is recorded or not 200 is returned.
* Returns true if ga was contacted.
*/
function my_ga_fire_hit( $user_id, $data ) {
if ( !defined( 'GOOGLE_ANALYTICS_ID' ) )
return;

$defaults = array(
'v' => 1,
'tid' => GOOGLE_ANALYTICS_ID,
'cid' => my_ga_user_id($user_id)
);

$payload_data = array_merge($defaults, $data);
$endpoint = 'https://ssl.google-analytics.com/collect?';
$parameters = http_build_query( $payload_data );
$result = wp_remote_post( $endpoint . $parameters );
if ( isset( $result['response'] ) ) {
return ( $result['code'] == 200 );
}
return false;
}

/**
* Save the google analytics UUID.
*/
function my_ga_parse_user($my_user_options) {
if ( is_user_logged_in() && isset($_COOKIE['_ga'])) {
$my_user_options = get_user_meta($user_id, 'my_user_options', true);
if ( empty($my_user_options) ) {
list($version,$domainDepth, $id, $ts) = split('[.]', $_COOKIE["_ga"], 4);
$contents = array('version' => $version, 'domainDepth' => $domainDepth, 'cid' => $id . '.' . $ts);

//3rd spot is the cid according to multiple sources
$my_user_options['ga_cid'] = $contents['cid'];

update_user_meta( $user_id, 'my_user_options', $my_user_options);
}
}
}
add_action('template_redirect', 'my_ga_parse_user');

/**
* Return the ga cid. (or what will be called user_id)
*/
function my_ga_user_id($user_id) {
$my_user_options = get_user_meta($user_id, 'my_user_options', true);
$cid = isset( $my_user_options['ga_cid'] ) ? $my_user_options['ga_cid'] : '';
if ( empty( $cid ) ) {
$my_user_options = my_ga_parse_user($my_user_options);
$cid = isset( $my_user_options['ga_cid'] ) ? $my_user_options['ga_cid'] : '';
}
return $cid;
}

/**
* Don't copy over _ga_tracked meta.
*/
function my_ga_remove_renewal_order_meta( $order_meta_query, $order_id ) {
$order_meta_query .= " AND `meta_key` NOT IN ("
. "'_ga_tracked' ) ";
return $order_meta_query;
}
add_filter ( 'woocommerce_subscriptions_renewal_order_meta_query', 'my_ga_remove_renewal_order_meta', 10, 2);

/**
* Let ga know a subscription payment has been processed.
*/
function my_ga_track_payment( $order_id ) {
$order = new WC_Order( $order_id );
if ( empty($order) || get_post_meta( $order->id, '_ga_tracked', true ) == 1 || !defined('GOOGLE_ANALYTICS_ID') )
return;

$tracking_id = GOOGLE_ANALYTICS_ID;
if ( empty( $tracking_id ) )
return;

$user_id = $order->customer_user;

my_ga_fire_hit( $user_id, array(
't' => 'transaction', // Transaction hit type.
'ti' => $order->get_order_number(), // transaction ID. Required.
'ta' => get_bloginfo('name'), // Transaction affiliation.
'tr' => $order->get_total(), // Transaction revenue.
// Transaction shipping. (not required)
'tt' => $order->get_total_tax() // Transaction tax.
) );

if ( $order->get_items() ) {
foreach ( $order->get_items() as $item ) {
$_product = $order->get_product_from_item( $item );
$_category = "";
if ( isset( $_product->variation_data ) ) {

$_category .= woocommerce_get_formatted_variation( $_product->variation_data, true );

}
else {
$out = array();
$categories = get_the_terms($_product->id, 'product_cat');
if ( $categories ) {
foreach ( $categories as $category ){
$out[] = $category->name;
}
}
$_category .= join( "/", $out);
}
$item_name = $item['name'];
// If we have a child renewal order, we need the original order's ID
if ( WC_Subscriptions_Renewal_Order::is_renewal( $order_id, array( 'order_role' => 'child' ) ) ) {
$original_order_id = WC_Subscriptions_Renewal_Order::get_parent_order_id( $order_id );
$original_order = new WC_Order( $original_order_id );
$order_items = WC_Subscriptions_Order::get_recurring_items( $original_order );
if ( !empty( $order_items ) ) {
$order_item = end($order_items);
$item_name = sprintf( __( 'Renewal of "%s"', 'lis' ), $order_item['name'] );
}
}

my_ga_fire_hit( $user_id, array(
't' => 'item', // Transaction hit type.
'ti' => $order->get_order_number(), // transaction ID. Required.
'in' => $item_name, // Item name. Required.
'ip' => $order->get_item_total( $item ), // Item price.
'iq' => $item['qty'], // Item quantity.
'ic' => $_product->get_sku() ? __( 'SKU:', 'woocommerce' ) . ' ' . $_product->get_sku() : $_product->id, // Item code / SKU.
'iv' => $_category // Item variation / category.
) );
}
}

update_post_meta( $order->id, '_ga_tracked', 1 );

}
add_action( 'woocommerce_payment_complete', 'my_ga_track_payment');

/*
// set next payment ot be in 5 minutes.
function my_ga_debug_next_payment() {
$subscription_key = '1234_5678';
$user_id = '1';

$next_payment_date = WC_Subscriptions_Manager::get_next_payment_date($subscription_key, $user_id, 'timestamp');
$new_next_payment_date = strtotime("+5 minutes");

if ($next_payment_date > strtotime("+7 minutes") ) {
//update the next payment date for referrer
$ret = WC_Subscriptions_Manager::update_next_payment_date($new_next_payment_date, $subscription_key, $user_id);
}

}
add_action('init', 'my_ga_debug_next_payment');
*/

Filed Under: Coding Tagged With: eCommerce, google, google analytics, php, woocommerce, wordpress

OSCommerce admin pages show 401

November 27, 2012 by Webhead

Problem

The OSCommerce admin pages were working fine a couple months ago.  Now I go to it and it shows a 401 error.

Solution

The problem was that the htaccess file had a rewrite added to it to always include www to the address.  Apparently the SEO guy did this.  The solution is to update the OSCommerce configuration files.  Meaning add “www” to the address variables in

includes/configure.php
includes/admin/configure.php

 

source: http://forums.oscommerce.com/topic/341940-how-to-change-htaccess-to-rewrite-the-url-hard/
http://forums.jaguarpc.com/design-development/24039-just-installed-oscommerce-admin-links-giving-401-authentication-failed.html

keywords: oscommerce 401

Filed Under: Coding, Server Stuff Tagged With: cms, eCommerce

LemonStand eCommerce Notes

November 22, 2011 by Webhead

Lemonstand is an eCommerce solution that lets you try before you buy.  It is very simple to use and virtually no learning curve to develop for.  It uses PHP and mySQL.  Check it out for yourself here.

Below are just a bunch of notes I jotted down while using and developing for Lemonstand.

Docs are located here:  http://lemonstandapp.com/docs/api_function_and_class_reference/
http://lemonstandapp.com/docs/developer_s_guide/

Editor buttons are editable in:

System/Settings/HTML Editor Settings

 

Enabling file-based tempaltes

  1. create an empty directory on the server – not web accessible, php writable
  2. Enable file-based templates on the System/Settings/CMS Settings page.

@font-face

If you need extra file extensions for fonts to be accessible, you need to edit the .htaccess file.
http://forum.lemonstandapp.com/topic/760-font-face/page__p__3768__hl__fonts__fromsearch__1#entry3768

 

Global Content

http://forum.lemonstandapp.com/topic/2392-global-editable-region-how-to/page__p__11010__hl__%2Bpartial+%2Bcontent_block__fromsearch__1#entry11010

 

 

 

 

Filed Under: Off the Shelf Tagged With: eCommerce, mysql, php

Magento eCommerce Solution Notes

October 26, 2011 by Webhead

On install

I got an error that said the php_pdo_mysql extension is required.  I added the extension to php.ini, restarted apache, and tried again.

 

I got an error similar to this:

Exception printing is disabled by default for security reasons.

Error log record number: 600807966

 

I looked around the web and found that to display errors, you need to rename MAGENTO_ROOT/errors/local.xml.sample to MAGENTO_ROOT/errors/local.xml.  Then errors can be displayed.

 

Then got an error similar to:

“SQLSTATE[42000]: Syntax error or access violation:  1067 Invalid default value for ‘period'”

Found the solution at:

http://www.magentocommerce.com/boards/viewthread/263672/

ALTER TABLE `coupon_aggregated` CHANGE COLUMN `period` `period` DATE NOT NULL DEFAULT ‘0000-00-00’

 

Finally it installed!

 

Watching the Magento U Video:

I signed up for Magento U and started to watch the video.  The first thing the developer in the video says is how difficult and frustrating Magento is…. Not very encouraging to developers starting out.  He warns of how he stayed up late nights figuring out the complexities of Magento.   That’s not too bad if it’s something you really want to learn.

However, in later videos he mentions that Magento 2 fixes some quirks in the current version of Magento.  Upon further Googling, I have found that Magento 2 is coming out in Mid – 2012.  That is maybe 7 months away from the time of this writing.   Then, the fact that breaks all backs, Magento 2 will be a total REWRITE!.  Which means everything learned today will most likely be thrown away or just used “in theory” for the future.  To me stressing out on something complex only to use it for 7 months, then learn a whole new system is not worth it.  This is why I chose to use LemonStand.

Filed Under: Off the Shelf Tagged With: eCommerce, magento

eCommerce Platforms

July 23, 2011 by Webhead

I’m in the hunt for a e-commerce open source framework that is easy to use and easy to extend.  Wordpress is the perfect combination of easy to use and easy to extend.  It also has great community support.  Before WordPress I used ExponentCMS.  While that is a good CMS, it is nowhere near the level of WordPress.   I customized Exponent for a client and it did not turn out very well.   Research to find the best platform the first time around can save a lot of time, money, and headaches.  This post is from one day’s research.

 

Magento

Not Magneto, like I thought it said before I saw a YouTube video.  lol.  This open source eCommerce system is professional to say the least.  With all the options in the admin panel, it looks like you could create your ownl eBay/Amazon site.  Reviews have all been in line with it looking professional and being very flexible, but they have also said that it is overly complex and difficult to modify.  They have a lot of coding standards and very little support from the core developers on the forums.  Even experienced developers will have a hard time with it.   If the website is for a large client, this may be the one for you.  On a side note, Ebay has recently purchased Magento.

Scroll to the bottom of http://www.magentocommerce.com/demo and see the community demo.

 

Open Cart

This seems like it has almost as much features as Magento, but is praised by many as having an organized structure.  It follows the MVC (model view contoller) framework so it’s less complicated.  The ease of the framework lets it to be easier to extend.  Google insight shows that it is the most searched PHP open source eCommerce platform.

Demo here: http://www.opencart.com/index.php?route=demonstration/demonstration

 

BigCommerce ($24/month)

Upon looking at review sites I ran into some that included commercial products.  I decided to put this here because this was named the best eCommerce platform of 2011 by a couple websites.  They feature drag and drop customization of the layout and many many other features.   I haven’t done the free trial yet, but it  seems as though they got the usability and the depth right.

A video tour is available here: http://www.bigcommerce.com/ecommerce-solution-features.php

 

OsCommerce

I have heard some horrible things about this CMS including things like it’s out of date, table-based, and not modular.

 

ZenCart

I have heard that this shopping cart is based on osCommerce.  The performance and code is supposedly not very good.

 

LemonStand

From the demo, this PHP-based ecommerce solution looks easy to modify.  The templates seem like they are in a easy to understand structured format.  It does have some, although not that great, CMS capabilities.  The cost to use this is $300.   I have chosen to use LemonStand as my ecommerce solution. because of its simplicity in implementing custom themes.  They have great documentation that lets you jump in and start creating your online ecommerce solution.   I have some raw notes on lemonstand here.

 

Filed Under: Off the Shelf Tagged With: eCommerce, php

Primary Sidebar

Topics

apache apple block editor chrome cms css debug eCommerce embed firebug firefox git gmail goDaddy google hosting htaccess html html 5 IE crap image iPad iPhone javascript jquery linux localization mac os x ms sql mysql open source optimize php php 5.3 responsive rest api seo svg tinymce woocommerce wordpress wpengine xss yii youtube




Categories

  • Coding
  • Off the Shelf
  • Plugins
  • Random Thoughts
  • Server Stuff
  • Tools