Restricting WooCommerce shipping rates by order value

Sometimes you may want to limit the availability of rates depending on the order value. The WooCommerce Pro Shipping plugin already lets you set up tiered rates by weight, or item quantity, but there’s no way to set a maximum order value for a particular rate. Fortunately there are filters in place that let you achieve that fairly easily. The example below limits a specific rate to a maximum order value of £100 after discounts, including tax – the rate won’t be offered if the cart is worth more than that.

add_filter( 'woo_ps_availability', function ($availability, $rate, $rate_id) {
    // Adjust '1' below to the rate ID to be blocked
    if ( $rate_id == 1 ) {
        // You may need to adjust this depending on whether your threshold is before/after discounts and/or before/after tax
        $total = WC()->cart->get_cart_contents_total() + WC()->cart->get_cart_contents_tax();
        if ( $total > 100) {
            return false;
    return $availability;
}, 10, 3);

Enabling multi-lingual string replacements without a multilingual plugin

WordPress has had support since version 4.7 for admin users to choose the language that they wish to use the admin area in, separate from the language used to display the front-end of the site.

It’s possible for you to run a site where the administration users interact in English, but the front-end of the site is displayed in a different language, e.g. French. This kind of setup doesn’t require the use of a multi-lingual plugin since front-end content only exists in one language.

By default, Say What? Pro only enables per-language string replacements if it detects a compatible multilingual plugin active on the site. However, if you’re running a dual-language setup using the built in WordPress user language selection, you can enable the features by adding a small plugin to your site:

 * Plugin Name: Language-specific replacements for Say What? Pro
 * Plugin URI:
 * Description: Enables language-specific replacements in the Say What? Pro plugin
 * Version: 1.0
 * Author: Ademti Software Ltd
 * Author URI:

add_filter( 'say_what_multilingual_enabled', '__return_true' );

Once this is installed, and active, you’ll be able to set replacements per-language as if you were running a multi-lingual frontend.

Replace words across whole site

Some of our users have asked us what is the best way to replace a word across their whole WordPress site. This isn’t something that our string replacement plugin “Say What? Pro” has traditionally been a good solution for. It normally works on full sentences, rather than individual words, so you would swap one sentence for another.

However, the new “wildcard swaps” feature allows you to do just that. Simply enter part of a string or word, and replacements will be carried out across all translatable strings on the site . These swaps are evaluated for every single string on your site, so they’re not the most efficient things in the world, and we’d always recommend proper full replacements where possible.

They can also lead to some interesting results if you’re overly broad with what you replace. For example here’s what happens to the WordPress “Users” menu if you set up a swap for “Use” to “Choose”. However – pick your strings carefully and it can be a useful way of replacing a wide range of strings without having to set up specific replacements for each sentence.


Override Twitter share message per product

Sometimes you may want to customise the sharing message per product when creating sharing links with the Social Checkout for WooCommerce plugin. The plugin includes filters to allow you to change the message however you want.

The snippet below shows how you can provide a custom message for a specific product – of course you can make this logic as simple – or as complex as you like:

function lw_woocommerce_sc_twitter_message( $message, $order, $product ) {
    if ( $product->id == 248 ) {
        return 'Custom message for product 248';
    return $message;
add_filter( 'woocommerce_sc_twitter_message', 'lw_woocommerce_sc_twitter_message', 10, 3 );

Exclude specific items from Social Checkout

The Social Checkout for WooCommerce plugin lets you create sharing links for the items in a customer’s cart. Sometimes you might want to exclude specific products from this list.

The plugin includes filters that let you override the list of items to be shown. Here’s a sample that excludes product ID 411 from being shown – obviously you can code up whatever logic you need.

function lw_woo_sc_order_line_items( $items, $order ) {
    foreach ( $items as $key => $item ) {
        if ( $key == 411 ) {
            unset( $items[ $key ] );
    return $items;
add_filter( 'woo_sc_order_line_items', 'lw_woo_sc_order_line_items', 10, 2 );

Changing the separator in the export files

Sometimes you may want to change the separator in the order export files produced by the WP e-Commerce Export plugin. Fortunately you can override the separator with a simple filter.

Just drop the snippet below into a plugin, or your theme’s functions.php file. This example uses a semi-colon (;) as a separator – but you can use any character you need.

function lw_ses_wpscd_csv_separator($sep) {
	return ';';
add_filter('ses_wpscd_csv_separator', 'lw_ses_wpscd_csv_separator');

Removing shipping dimensions from WooCommerce Google Product Feed

The following snippet will let you remove all shipping dimensions from the WooCommerce Google Product feed.

function gpf_remove_shipping_attrs($elements, $product_id) {
	return $elements;
add_filter( 'woocommerce_gpf_elements_google', 'gpf_remove_shipping_attrs', 11, 2 );

Simply drop it into your theme’s functions.php file if you’re using a child theme, or add it to a Functionality plugin.

Adding extra parameters to URLS in WooCommerce Google Product Feed

Sometimes you’ll want to add additional information to the URLs that your site submits to Google Merchant Centre. This can be important because you want to track the URLs – or have the page jump to relevant information for users coming through product ads.

There are filters in the plugin that allow you to alter the information that is used for any particular product. The simple example below adds a query argument of “queryArg” with a value of “myValue” to all product URLs.

function lw_woocommerce_gpf_feed_item_google( $feed_item ) {
    $feed_item->purchase_link = add_query_arg(
        array( 'queryArg' => 'myValue' ),
    return $feed_item;
add_filter( 'woocommerce_gpf_feed_item_google', 'lw_woocommerce_gpf_feed_item_google' );

Backwards compatibility for text-domain changes is currently importing language packs for plugins into their central system, allowing them to be managed and downloaded separately rather than having to bundle everything with plugins. One of the knock on effects to this process is that some plugins are required to change their text-domain.

As an example, easy digital downloads is having to change from a text domain of “edd” to “easy-digital-downloads”. Unfortunately this would ordinarily cause any string replacements you’ve set up to stop working – since the strings being offered for replacement no longer match what you would have set up in Say What?

Fortunately, the Say What? plugin allows domain aliases to be configured so that a plugin can register the fact that their new text domain was previously something else, and then Say What? can continue to use your existing replacements. If you’ve come across a plugin that has changed its text domain and replacements no longer work, then a code snippet like this will allow you (or the plugin author) to map the domains for you.

function edd_say_what_domain_aliases($aliases) {
    // Add a mapping from your new domain to the old.
    $aliases['easy-digital-downloads'][] = 'edd';
    return $aliases;
add_filter( 'say_what_domain_aliases', 'edd_say_what_domain_aliases' );

Fortunately for Easy Digital Downloads users – the plugin already includes this for you – so the whole process should be seamless as long as all of your plugins are up to date. Hopefully this post will let you map any changed domains yourself, or get changes implemented into plugins of your choosing.

Remove sale price from WooCommerce Google Product Feed

There are some situations where you don’t want to include the sale prices for products – for example where legal, or contractual restrictions mean that you can only advertise the products at full price.

The standard behaviour of the WooCommerce Product Feed plugin is to include both the regular price, and sale price – however with a small filter you can exclude the sale  price from being sent. Just drop the snippet below into your theme’s functions.php file – or a Functionality Plugin.

function lw_remove_sale_price($item) {
    return $item;
add_filter( 'woocommerce_gpf_feed_item', 'lw_remove_sale_price' );

Setting default shipping option with WooCommerce Pro Shipping

WooCommerce Pro Shipping lets you set up multiple different rates, each of which can have different pricing rules, availability rules, destinations and minimum / maximum thresholds. This means that WooCommerce’s built in default “default shipping” choices – which only let you choose “Pro Shipping” aren’t quite sufficient.

However, WooCommerce does include a filter that can be used to set a default shipping choice. In our example, we’ve got a number of different rates set up.

Screenshot 2015-04-27 18.35.23


We’re going to make WooCommerce choose “Value Pricing” (rate ID 4) as the default if it’s available, otherwise falling back to “Quantity Pricing” (rate ID 3), or just WooCommerce’s normal “cheapest rate” choice if neither are available. The following code should be added to your theme’s functions.php file or a functionality plugin.

function lw_woocommerce_shipping_chosen_method( $method, $available_methods ) {
    // Don't do anything if a method is already selected.
    if ( ! empty( $method ) ) {
        return $method;
    // Get the IDs of the methods that are available.
    $methods = array_keys( $available_methods );
    // Our preferred methods. The first method in this list that is
    // available will be defaulted.
    $preferences = array(
        'pro-shipping-4-0', // pro-shipping-{rate_id}-0
    // Search the preferred options and return it if it's available.
    foreach ( $preferences as $preference ) {
        if ( in_array( $preference, $methods ) ) {
            return $preference;
    return $method;
add_filter( 'woocommerce_shipping_chosen_method', 'lw_woocommerce_shipping_chosen_method', 10, 2 );

Excluding individual bundled products

The Product Bundles add-on from WooCommerce allows you to bundle multiple products into a group for sale. Usually, when these are purchased, the Social Checkout for WooCommerce plugin will show sharing links for the bundle product, and all of the individual items in the bundle as well. If you would prefer to just show the main bundle product, and not the individual items, then adding the following snippet to your theme’s functions.php file, or a functionality plugin will exclude them from having sharing links shown.

function lw_woo_sc_order_line_items( $items, $order ) {
    foreach ( $items as $key => $item ) {
        if ( ! empty( $item['item_meta']['_bundled_by'] ) ) {
            unset( $items[ $key ] );
    return $items;
add_filter( 'woo_sc_order_line_items', 'lw_woo_sc_order_line_items', 10, 2 );

Overriding shared product information

By default, the Social Checkout for WooCommerce plugin shares the main product image, the product title, and the standard product URL. In some situations you may want to override those values with something else. Perhaps you want to provide a more engaging product title – or direct customers to a special Social Media focussed landing page for a product.

The plugin provides filters for you to change the information that is used. The filter receives the calculated values for the item, the product that’s being shown (Note: this may be empty if an order contains more than five items and a single share link is being shown), and the full WooCommerce order.

In the following example, we’re overriding the product URL to send shares to a specific product landing page.

function lw_woo_sc_item( $item, $product, $order ) {
    $item->permalink = '';
    return $item;
add_filter( 'woo_sc_item', 'lw_woo_sc_item', 10, 3 );

You can change any of the following properties on the item object:

  • image
  • title
  • permalink

Adding custom field to payment export

The EDD Payment Export & Reports plugin allows you to export details of your customers orders to a CSV. The plugin contains support for most of the standard Easy Digital Download payment fields out of the box, as well as supporting information from well-known EDD extensions such as Software Licensing.

Sometimes however, you may have custom checkout fields that you want to export alongside the standard fields. In this case, you can alter the behaviour of the plugin to include your fields via a set of WordPress filters. These will let you register additional fields, and specify how they the output for those fields should be gathered / calculated. Simply drop these into your theme’s functions.php file or a functionality plugin, then you’ll be free to keep updating the main plugin without fear of losing your changes.

In the example below we’re going to create a “Full name” field that will simply concatenate the first, and last name of the purchases.

There are two functions you’ll need to define. The first registers the field with the plugin, making it available to choose for export. This function also tells the plugin what function it should call to generate the output for this field.

public function lw_edd_dash_export_fields( $fields ) {
    // Make the key here unique.
    $fields['my_custom_field'] = array(
        // This is the field name, displayed on the export screen.
        'title' => __( 'Customer Full Name', 'edd_dash' ),
        // Specify whether the field is available on order summary and / or order line exports.
        'display_on' => array( 'order_summaries', 'order_lines' ),
        // A function that outputs the data for this field for an individual payment record.
        'generator' => 'lw_render_my_field' ),
add_filter( 'edd_dash_export_fields', ‘lw_edd_dash_export_fields' );

Here – we’ve defined a new field that will show up as “Customer Full Name” on the export screen, and in the heading of the column in the CSV. When the plugin generates the CSV, it will call the function lw_render_my_field() to generate the output for our field.

 * This function will be called for each line to produce the output for this field.
function lw_render_my_field( $payment ) {
    // Return the output for this field for $payment
    // Put your logic here.
    return $payment->user_info['first_name'] . ' ' . $payment->user_info['last_name'];

Our “rendering” function will be passed a $payment variable which will contain the basic information about the payment already. Here we’re picking up the first and last name, and returning them as a single string. Of course – you could load up a custom value here, and return that if you have something specific you want to grab.

Restricting WooCommerce shipping rates by weight

Sometimes you want to provide rates but limit their availability based on the weight of the order – for example if your carrier only carries packages up to a certain weight.

The WooCommerce Pro Shipping plugin already lets you set up tiered rates by weight, or item quantity, but there’s no way to set a maximum weight for a particular rate. Fortunately there are filters in place that let you achieve that fairly easily.

The example below limits a specific rate to a maximum weight of “5” – the units are whatever your store base weight unit is set to, e.g. if your store is set up to use kilograms, this will block the specific rate (ID 1 in our example below) over 5kg.

function limit_rate_by_weight( $availability, $rate, $rate_id ) {
    global $woocommerce;

    // The limit must be specified in your base store weight units.
    $limit = 5;

    // The rate ID of the rate you want to block.
    $blocked_rate_id = 1;

    // Retrieve the cart weight
    $weight = $woocommerce->cart->cart_contents_weight;

    if ( $rate_id == $blocked_rate_id ) {
        if ($weight > $limit) {
            return false;
    return $availability;
add_filter( 'woo_ps_availability', 'limit_rate_by_weight', 10, 3 );

Make scheduled exports include all data

When running scheduled exports with the WP e-Commerce dashboard & export plugin, the default behaviour is that the export will include all data created sine the export last ran. Sometime you may want your exports to include a full picture of all data, not just those items changed since the last run.

The plugin allows you to control the time used for the start of the data, so by overriding that you can make your sales export include all data. Here’s an example code snippet that can go in your theme’s functions.php or in a functionality plugin.

function lw_ses_wpscd_cron_export_start_time( $last_export_time, $schedule_id ) {
    return 0;
add_filter( 'ses_wpscd_cron_export_start_time', 'lw_ses_wpscd_cron_export_start_time', 10, 2 );

Defaulting the shipping country at checkout with WP e-Commerce

The latest versions of WP e-Commerce no longer default the shipping country when a customer first arrives at checkout. If you want to reproduce this behaviour you can still do so by adding a small snippet of code to your theme’s functions.php file, or by using a functionality plugin. Here’s a snippet that defaults the country to the store base country.

function lw_wpsc_get_visitor_meta( $value, $key ) {
    if ( $key == 'shippingcountry' &amp;&amp; empty( $value ) ) {
        $value = get_option( 'base_country', TRUE);
    return $value;
add_filter( 'wpsc_get_visitor_meta', 'lw_wpsc_get_visitor_meta', 10, 2 );

Limiting orders included in Freshdesk

The EDD Payment status is included in the order view in Freshdesk, but sometimes you may want to limit the orders that are shown to those in particular statuses.

By default, orders in any of the following statuses are included:

  • Pending
  • Complete
  • Refunded

The EDD Freshdesk plugin contains a filter that lets you control which order statuses are included in the feed to Freshdesk, so you can include code like the below in your theme’s functions.php file, or a functionality plugin to limit the orders that are included. For example, if you want to limit just to Complete orders, you can do the following:

function my_plugin_edd_freshdesk_order_statuses($statuses) {
	return array('publish');

Shipping cost not passed to PayPal

PayPal appear to be experiencing a temporary issue where shipping / handling costs passed across to them aren’t taken into account – leading to orders effectively having no shipping charge when PayPal process the order.

If you’re using WP e-Commerce with PayPal and are hitting this issue, then adding the following snippet to your theme’s functions.php file should work around the issue for now.

function tmp_fix_wpsc_paypal_standard_post_data($args ) {
    $args['shipping_1'] += $args['handling_cart'];
    $args['handling_cart'] = 0;
    return $args;
add_filter('wpsc_paypal_standard_post_data', 'tmp_fix_wpsc_paypal_standard_post_data');

For the technical among you – PayPal seem to be ignoring costs passed in the handling_cart variable. This snippet simply adds what should be in that variable to the shipping cost of the first product in the cart, and zeroes the handling_cart. It’s only intended as a temporary fix, and should be removed when PayPal have resolved the issue.

Replacing WordPress strings with “context”

When writing a WordPress plugin, programmers occasionally have strings that they want to mark for translation, but the same string can mean different things in different places.

For example you might want to refer to “Pounds” as a unit of weight, and “Pounds” as the shorthand for the British currency. In that case you can provide additional context that translators can use to determine which “pounds” you mean in case the translation is different.

So, while a simple use of a translated string includes only the string, and the text domain, and doesn’t require you to provide a context:

__('Pounds', 'plugin-domain');

If you wanted to provide context in different use cases, you can use the _x() function and provide the context as an extra argument:

_x('Pounds', 'Unit of weight', 'plugin-domain');
_x('Pounds', 'The British currency', 'plugin-domain');

Translators can provide different translations for each of these strings.

sw-wcontextIf you’re looking to provide an alternative string using the Say What string replacement plugin then you need to know the domain, and the context of the string you’re looking to translate. So – adding a replacement string with a context of “Unit of weight” as per this screenshow, would only replace the first string in our example – the currency string would remain unaffected.

If you wanted to replace the second string, then you’d add it as a second replacement, using “The British currency” as the context value.

Of course – if the string you’re trying to replace using the standard _() or _e() functions, and doesn’t have a specific context, you can just leave the text context field blank.