Extend notification emails in wp-e-commerce

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.

  • This is exactly what I was looking for! Thanx very much!! :-)

    We have a lot of different free “fixed rates” … is it possible to add this information also to the email that goes to the customer?

    Please have a look at: http://www.kaffeekultur-wussler.de/main/products-page

    Thanx very much!! :-)

  • G’day Roman, the hooks you want for the customer’s email message are wpsc_transaction_result_message and wpsc_transaction_result_message_html, and they have the same placeholders as the transaction report message. Note that the second one is HTML though. Hmmm, coffee… must be time for a cup :)

  • Very nice. Helped a ton. I’m having to curl an outside webservice to get a license number for the downloadable product. This gets me 95% of the way towards adding the returned license number to the emails. Appreciate your post!

  • Stuart

    I have been looking for this for some time – thanks for the info.
    I am by no means an expert in PHP or CSS but I would love to implement this on my site. Please can you let me know where exactly the file is to past the code in?

    Much appreciated.

    • G’day Stuart, the easiest way is to add it to your theme. Edit the functions.php file in your theme folder, something like:


      NB: when you update your theme, it will delete this code so you’ll need to add it back. A better way is to customise a theme, or write a plugin, but you can learn how to do that after you get a bit of PHP under your belt :)

  • Elo


    That’s also exactly what I was looking for !

    I pasted your code in my functions.php > the shipping costs appear in the customer confirmation email, but I don’t receive anymore the admin confirmation email.

    Do you have an idea of the problem ? Something else to customize ?

  • Elo

    Sorry, the emails has just arrived, but a long time after the others : )

    However, in this one, I can see the nature of the shipping options, but not the amount.

    Do I need to change something in the code ?

    • G’day Elo, it should give your something like this at the end of the admin email:
      Express Post (estimated delivery time: 1 business day)

      Total Shipping: $19.75
      Total: $69.75

      If it doesn’t, does your Admin Report email template look like this? (It’s in the WordPress admin, under Settings->Store->Admin)

      Also, what version of wp-e-commerce are you running?

  • Elo

    Hello Rmckay, thank you for your reply.

    Version of wp-e-commerce is running on my website.

    And yes, in the admin, I have the 3 items, including : %product_list%%total_shipping%%total_price%

    And at the end of the admin report email, I only have :
    “Shipping : Weight Rate
    Total: 80.95 €”
    But no amount of the shipping.

    I don’t know where / how to investigate now (?)

    • G’day Elo, what happens if you comment out line 50 above?

  • This is a very good info. Hard to find. Thanks.

  • Hello,
    This is a beautiful work!
    Something worry: the hook functional normally, but…
    product is “A”.
    The Customer select the “A” pruduct, with product options and “add to cart”,
    and select one more “A” product, with different product otions, and “add to cart”,
    and “send an order”.
    I arrive the admin report, i see: the Customer purchased 2 x “A” products, but the admin email send me only the 2. “A” product “product option”.
    It would be important to me, I get the both “product options”.
    Thank you very much for help!
    (Sorry for my bad english.)
    Thanks: Peter from Hungary

    • G’day Peter,

      I tried on a test site, with a product that has options of Red, Green and Blue. My email gives me a separate line for each option selected.

      Can you tell me please:

      • what version of wp-e-commerce you have
      • the Admin Report email template from Settings/Store/Admin*
      • whether this problem still happens without the code above

      * e.g. the standard one is %product_list%%total_shipping%%total_price%

      • Hello Ross,
        Thank You for reply.
        The wp version: 3.4.1
        The e-commerce version:
        The Admin report: %product_list%%total_price%
        ( Here ist pizza delivery, therefore no “total shipping”)

        E.g. if You order 1 pizza ( http://pizzanetzuglo.hu/?wpsc_product_category=pizzak ) and selection “product options”, and you send the Order. I received the admin email, and i see: 1 pizza, product options: i see the 7 pizza toppings.

        But, You order 2 pizzas, i see in admin report (email) only second pizza topping (that is i see NOT the first pizza toppings)
        Thanks: Peter

        • G’day Peter,

          I reckon you have something wrong with either your products or your templates. I tried with two products on the same page, each with two product options, and they both sent their selected options through in the emails.

          Perhaps you should ask for help on the wp-e-commerce support forums.


  • Victor

    Great work! Would it also be possible to include the shipping info and payment info (selected payment option + instructions) in the customer e-mail this way?

    • G’day Victor,

      Sure, the hooks you want for the customer’s email message are wpsc_transaction_result_message and wpsc_transaction_result_message_html, and they have the same placeholders as the transaction report message.


      • Victor

        Many thanks! Works out nicely!

    • Andrew

      Being a ‘bit’ of a noob here i wold greatly appreciate if you could explain in more detal how to add Payment option selected into email.


      • I don’t understand, wp-e-commerce already adds that information to the emails, it’s not something you need to add. If you are having a problem, perhaps you should ask for help on their support forums.

        • Andrew

          We partly customised wp e-commerce and added 2 new payment gateways for our local needs.

          I just need to add which payment gateway was selected into admin email so we know how to process the order.

          • G’day Andrew,

            The wpsc_transaction_result_cart_item hook gives you one parameter, which is an array (hash) with three items. One of them is purchase_log, which is another array (hash) detailing the purchase. It contains an element called gateway, which has the name of the selected payment gateway. So, add this line somewhere in function actionWpscTransResultContent():

            $this->wpscGateway = $item['purchase_log']['gateway'];

            Then you will be able to manipulate it in function filterWpscTransResultReport().


  • Hey Ross,

    You made my day. I was trying to find something on this & your code worked perfectly! Is there any way to find out the details of the order other than using


    I have currently used this to get the value of one of the custom fields to be sent to the customer.

    • G’day Ashok,

      Add this line into the function actionWpscTransResultContent() above, and you’ll be able to see all the information provided by that $item parameter:

      echo print_r($item,1);

      If what you need isn’t in there, then you’ll need to pull it from the cart yourself using wp-e-commerce function calls.


      • The line above should have the print_r() call wrapped in pre tags, but I can’t put them in through comments. So here’s the pastebin:


        • I understand what you mean. The $item will give me the information about the items in the cart. Is there any way I can get the information about the order, specially the order total?

  • Wow! Thank you for your snippet. This is really helpful.

    Besides, I need to write a sales log in csv format to server, for the connection of in-house’s automatic ordering. I was thinking to add a function and to run after IPN process. I’m using PayPal Standard Merchant gateway.

    Do you have any suggestion, where is the best location to execute it?

    • G’day jialing, I haven’t had anything to do with that payment gateway, but I can tell you that there are three actions you can hook that can help you get your data: wpsc_payment_successful, wpsc_payment_failed, and wpsc_payment_incomplete. I reckon that if you hook action wpsc_payment_successful, you should be able to access the information you want from the global variable $purchase_log.


  • Jialing

    Hi Ross,
    Thank you for your prompt reply. And I understand the best location is to hook up with wpsc_payment_successful.
    However, the way to hook action with wpsc_payment_successful puzzled me.

    Such as, I have a customized function called purchase_log_output_csv() (in my template/function.php, and it’s working properly from direct call).

    Is it correct to add the function in wpsc-includes/merchant.class.php at around code #280?

    switch ($purchase_log[‘processed’]) {
    case 3:
    // payment worked
    purchase_log_output_csv() ;

    Or there is other way, the best to hook additional action after wpsc_payment_successful?

    Thank you and appreciate for your reply. :)

    • G’day Jialing,

      First rule of customising someone else’s plugin: don’t edit that plugin! (OK, there are exceptions, but it’s the first rule!) If you change the plugin, and then you/someone else updates it, you lose your changes.

      Customising WordPress, and most plugins, is done using action and filter hooks. WordPress has lots of hooks, and most plugins have some too. Even when a plugin doesn’t have the hooks you want, you should still try to use hooks.

      In the code above, in your comment, that line do_action('wpsc_payment_successful'); is calling an action hook. To trap it in your theme, you just need to hook in your function (add this to your functions.php):

      add_action('wpsc_payment_successful', 'purchase_log_output_csv');


  • Jialing

    Thank you very much…It’s much easier than I thought!
    You are amazing and save my day. ^__^

  • Jialing

    Hi Ross,

    FYI only.
    This is for anyone who are using PayPal Standard Merchant gateway and looking for a solution.
    The odds is this payment gateway won’t fire ” wpsc_payment_successful”. Therefore, it needs to hook up with “wpsc_confirm_checkout” instead.

    The hook action needs to be: add_action(‘wpsc_confirm_checkout’, ‘purchase_log_output_csv’);
    And then check the ‘processid’ value ‘3’ for ‘accepted payment’.

    Hope this would help other people as well…

    • Good work, Jialing. Thanks for sharing what you found.


  • I am not very experienced in php, but I could use some help with this code. I would like to send the same information to customer’s e-mail, but can’t figure out, what exactly do i have to change. Could you maybe show me the exact code?

    Thanks in advance,

    • G’day Mihkel,

      See my reply to this comment, above.


      • Thanks Ross, I noticed that, but the trouble is, I actually don’t understand, where do I have to use these hooks in the code… I tried replacing them, but it didn’t work…

        • G’day Mihkel,

          You should be able to just replace wpsc_transaction_result_cart_item with wpsc_transaction_result_message on line 11 of the code above. You put the code above into the functions.php file in your theme folder. If you want both the admin and the customer emails to have those changes, duplicate line 11 and change only the duplicate line.

          NB: please make a backup of your theme’s functions.php file first! If you are not comfortable making changes to PHP files in WordPress, perhaps you would be better served asking someone who is to make those changes for you.


  • steven

    Is there any way this can be implemented in the newest wp ecommerce. I cannot figure out how to add my checkout form custom fields to the purchase email receipt.

    • G’day Steven,

      I’ve been holding off even looking at v3.8.9 until the dust settles, which it apparently hasn’t yet because I see that v3.8.9.2 has just been released. I’ve just taken a look now, and it has changed a couple of things this post was addressing.

      Firstly, there is no need to handle shipping options, selected payment gateway, or personalised messages with the method above any more, because v3.8.9+ now includes these in the transaction report email. The client’s message also gets the personalised messages.

      The basis of the post above still works, however the transaction report has changed and can no longer be customised through Settings>Store>Admin>Admin Report. It also no longer has the placeholder %total_shipping%, which has now become %shipping%; however that’s probably not needed any more since the plugin now handles shipping options in the transaction report email.

      So, if you want to add shipping options, selected payment gateway, or other custom items into the client’s message, or customise the product list in the transaction report, you still can. You just might need to tweak things a little from what I wrote above.

      One point of concern: according to a code comment, apparently “Gary honestly doesn’t fully understand” why the action wpsc_transaction_result_cart_item is required for each item in the cart, so there may come a time when it is replaced with an action outside of the cart item loop in the new WPSC_Purchase_Log_Notification class (wp-e-commerce/wpsc-includes/purchase-log-notification.class.php), but hopefully it will still provide the information needed for customising emails.


      • steven

        Thanks for replying. I hadn’t seen your response and when i was looking agian to fix this issue, i came across your site again.

        the Transaction Reports do show alot more info now, but my problem is, the reports are sent for every transaction, no matter if its authorized or not.

        I’m trying to figure out how to only send the transaction report for an authorized payment, OR find a way to pass all my form fields to the customer receipt email, which i then bcc to the admin.

        • G’day Steven,

          The easy way is to put that data in the customer receipt email, which means just using these hooks instead: wpsc_transaction_result_message, wpsc_transaction_result_message_html.

          Otherwise, you’ll need to hook into the transaction confirmation process and work off that. There are hooks for that (another commenter discusses them above).


  • I’ve released a plugin to customize mails, transaction results and purchase receipts.
    Maybe some of you is interrested in trying and give me some feedback.
    wp ecommerce shop styling

    • G’day Hannes, looks very nice. I’ve moved on to WooCommerce (much nicer to use!) but will bear it in mind for next time I need to refresh one of my old wp-e-commerce client’s sites.


  • Raghav

    G’day Ross,

    I’m held up with a problem. I was searching for the solution and stumbled on your post.
    The problem: I’m using wp e-commerce latest version plugin. Say I have three products (1A, 1B, 1C) set up.

    I want three different emails to go based on the products purchased – I’ve to enter three different links (1A- Link1, 1B – Link2, 1C – Link3) in the mails which is respective for each product.

    As of now there is only one “Customer Purchase Receipt” in the admin section. If I put anything there that would go to all the buyers who purchase anything.

    So I want different emails to go to different buyers/products.

    Your post was inline – but I need some clarity on how to proceed.
    Please can you assist me.

    Regards and thanks in advance,

  • G’day Raghav, the filter ‘wpsc_transaction_result_cart_item’ is called for each item in the cart, so you can build a list of products from it. The when you process the report filters, you can check to see which product you got and add a link.

    If you want to replace the standard product list with your list of links, then simply replace ‘%product_list%’ with your custom list; WP e-Commerce won’t find it in the template once you’ve replaced it.

  • Raghav

    Am doing a subscription site with payment gateway integrated, which offers journals to the users –


    1. free – here he can access only one issue of each journals – there are 6 issues
    2. print – here he can access online ebook of all journals of all 6 issues
    3. web – here he can access only the pdf and ebook of all journals of all 6 issues

    The Subscription process as of now:

    1. Free user wants to become print or web subscriber
    2. He has logged in
    2a. If he has not logged in can create the account
    3. Goes to cart – since he is logged in – no need of again filling up the form
    3a.Not logged in – click the login button in top navigation
    4. He can directly click the add to cart – proceed to checkout
    5. Pay the money through payment gateway
    6. Admin will get a Order notification
    7. Admin checks has the payment been done from their account
    8. Confirms the payment – Customer gets the mail – His order has been processed
    9. Admin moves the Free User to Print/Web subscription
    10. Next login the free user will be print/web user

    Am using Wishlist membership plugin and Woocommerce shopping cart plugin.

    The Query is:
    When the subscription expires of the paid user(print or web) will again become a free user – how to renew his subscription with the same details – Is there a way once he pays – give him a link and he can update his membership.

    Is there a php hook, filter or function which can be included it happens automatically.

    Please assist.


    • G’day Raghav, that has absolutely nothing to do with this post. This post is about extending email notifications from WP e-Commerce; you’re using WooCommerce. I suggest you ask your question in an appropriate forum, not just some random guy’s blog post comments :)


  • Raghav

    I needed assistance as am new to the php world. Therefore was seeking your assistance as you are technical expert in php.


    • G’day Raghav, that’s all well and good, but you need to ask in the right forum. A blog is not a support forum. Specifically, a blog post about plugin A is not a support forum for plugin B :)


  • Hey Ross,

    It looks like you’ve added some awesome functionality to WPeC! I’m just trying to add some extra info to the new WPeC (… I’d like simply to add the customer’s name and delivery and billing addresses to their notification emails. Is this possible? I’ve been trying to follow the general thread here but so far without success.

    Any help GREATLY appreciated,

    • G’day Paul,

      You’d need to filter the message to add your information before it was sent; you can use the filter ‘wpsc_purchase_log_customer_notification_raw_message’ to do that in v3.8.9 and above. Its second argument is a reference to a log notification object, and you can get the purchase log from it by calling get_purchase_log(), e.g.

      $purchase_log = $log_notification->get_purchase_log();

      Getting the customer details is a little complex; I suggest you look at the code for WPSC_Purchase_Log_Admin_Notification::get_raw_message() in the purchase-log-notification.class.php file to see how they build it up for the admin notification message.


      • Hi Ross,
        Thanks for your reply – super quick!

        This seems a little more complicated than I thought – I’d really like to do it but might need a bit more info…
        RE: wpsc_purchase_log_customer_notification_raw_message, could you tell me exactly where the $purchase_log = $log_notification->get_purchase_log(); might go??

        I’ve found this in purchase-log-notification.class.php but am not entirely sure what to do to it…

        public function get_raw_message() {
        $raw_message = ”;

        if ( ! $this->purchase_log->is_transaction_completed() )
        $raw_message = __( ‘Thank you, your purchase is pending. You will be sent an email once the order clears.’, ‘wpsc’ ) . “nr”;

        $raw_message .= get_option( ‘wpsc_email_receipt’ );
        $raw_message = $this->maybe_add_discount( $raw_message );
        // pre-3.8.9 filter hook
        $raw_message = apply_filters( ‘wpsc_transaction_result_message’, $raw_message );
        return apply_filters( ‘wpsc_purchase_log_customer_notification_raw_message’, $raw_message, $this );

        Also, I’m afraid I can’t see – WPSC_Purchase_Log_Admin_Notification::get_raw_message() within the purchase-log-notification.class.php file…

        Thanks for your help so far and taking the time to reply!


        • G’day Paul,

          First of all, WPSC_Purchase_Log_Admin_Notification::get_raw_message() is in the purchase-log-notification.class.php file at line 331; note that there are four classes in that file. At lines 345-353, it collates the fields you need for the customer’s address details. Lines 388-402 build the HTML for the emails.

          What you need to do is add some code either to your theme’s functions.php file or to a simple plugin; I recommend the latter. You need to create a filter function for the filter “wpsc_purchase_log_customer_notification_raw_message”. That filter passes two parameters, the $raw_message that it will put into the email, and the $log_notification object that you can use to get access to the $purchase_log object. You can then build the HTML for your customer’s details, and add that to the $raw_message. Your filter function then needs to return the $raw_message.