Extend notification emails in wp-e-commerce

This post is more than 12 years old.

The wp-e-commerce shopping cart plugin is probably the most popular cart plugin for WordPress, but it isn’t always the most easily customised; in fact, theming it can be a nightmare. One little niggle I had to fix recently was that the notification emails don’t include relevant purchase information such as which shipping method was selected, or the per-item comments from the purchaser (e.g. a message to be included inside a book flap).

[Edit: v3.8.9 has changed things a little, so please read this comment below and any responses to it. I might need to write a new blog post about this later when time permits.]

Luckily, this plugin does actually provide a few hooks to let you customise the notification emails. If you look at the function transaction_results in the file functions/wpsc-transaction_results_functions.php, you’ll find some action and filter hooks that allow you to catch some of the missing information and add it to the email before it is sent.

First stop is grabbing the relevant information. I need to pick up the shipping method and each item’s custom message, so I need a hook that gives me access to each item in the cart. And wp-e-commerce provides wpsc_transaction_result_cart_item just for that purpose:

do_action( 'wpsc_transaction_result_cart_item',
 array( "purchase_id" => $purchase_log['id'], "cart_item" => $row, "purchase_log" => $purchase_log ) );

Next stop is injecting the extra information into the notification email. There are two different emails, the results message (which goes to the customer) and the transaction report (which goes to the vendor); I need to modify the transaction report so that the vendor knows how to send the products, and what the custom messages are. And wp-e-commerce provides wpsc_transaction_result_report for that:

$report = apply_filters( 'wpsc_transaction_result_report', $report );
$report = str_replace( '%purchase_id%', $report_id, $report );
$report = str_replace( '%product_list%', $report_product_list, $report );
$report = str_replace( '%total_tax%', $total_tax, $report );
$report = str_replace( '%total_shipping%', $total_shipping_email, $report );
$report = str_replace( '%total_price%', $total_price_email, $report );
$report = str_replace( '%shop_name%', get_option( 'blogname' ), $report );
$report = str_replace( '%find_us%', $purchase_log['find_us'], $report );

Notice that the text of the report has some keywords in it, which are replaced by the lines following the call to the hook. This gives us a way to inject our custom information into the email, in the place where we want it to go.

So, all I need is two hooks, and somewhere to store the information gleaned from the first hook until I need it for adding to the email in the second hook. On the site I implemented this, I added it to the class I use for customising the theme, in the theme’s functions.php file, but I’ll simplify it here.

class ExtendWpscEmails {

    private $wpscItemExtra = array();   // array of wp-e-commerce items with extra info
    private $wpscShippingOption = '';   // the selected shipping option, to report in cart emails

    /**
    * add our hooks as class methods, so that they can reference the private members above
    */
    public function __construct() {
        if (!is_admin()) {
            add_action('wpsc_transaction_result_cart_item', array($this, 'actionWpscTransResultContent'));
            add_filter('wpsc_transaction_result_report', array($this, 'filterWpscTransResultReport'));
        }
    }

    /**
    * hook into wpsc_transaction_result_cart_item action to store extra information for sales email message
    * @param array $item an array with keys purchase_id, cart_item, purchase_log
    */
    public function actionWpscTransResultContent($item) {
        // pickup any personalised messages for cart item
        $cart_item = $item['cart_item'];
        if (!empty($cart_item['custom_message']))
            $this->wpscItemExtra[$cart_item['name']] = $cart_item['custom_message'];

        // record the selected shipping option so that we can report that in the cart emails
        $this->wpscShippingOption = $item['purchase_log']['shipping_option'];
    }

    /**
    * filter wpsc_transaction_result_report customise the sales report email
    * @param string $report the sales report email text
    * @return string
    */
    public function filterWpscTransResultReport($report) {
        // add list of personalised messages for cart items
        if (!empty($this->wpscItemExtra)) {
            $extras = "Personalised messages:n";
            foreach ($this->wpscItemExtra as $name => $extra) {
                $extras .= "$name:-- "$extra"n";
            }
            $report = str_replace('%product_list%', "%product_list%nn$extrasn", $report);
        }

        // add selected shipping option
        if (!empty($this->wpscShippingOption)) {
            $report = str_replace('%total_shipping%', "n{$this->wpscShippingOption}nn%total_shipping%", $report);
        }

        return $report;
    }
}

// create an instance (hooks will keep it alive)
new ExtendWpscEmails();

Simple enough, maybe not pretty, but job is done and the vendor has the information they need without having to visit their own website for the extra information.

Edit: there’s also a gist that extends WP e-Commerce customer emails to add shipping and billing details.