How to Dequeue Scripts and Styles in WordPress for Improved Page Speed

Many WordPress plugins load scripts and styles on every page of a website even though they may just be needed on a few specific pages. For example, WooCommerce loads at least 3 scripts and 4 styles on every page, even if ecommerce functionality (like a cart or products) aren’t shown on those pages.

I recently went on a performance rampage at Universal Yums and removed ~300kb of enqueued assets that were not needed on our home page- which shows there can be quite a bit of fat to trim.

To find our which scripts and styles are enqueued, you’ll need to do a some detective work. First, install the Query Monitor plugin. This will let you know which scripts and styles are enqueued for a specific page.

Screenshot of site with Query Monitor running

Query monitor will show you all the scripts enqueued by WordPress for a specific page. It will also show you the “handle”, which is needed to dequeue the asset.

To dequeue scripts you can use the wp_print_scripts hook.

/**
 * Remove scripts that have been enqueued by other plugins.
 */
function prefix_remove_scripts() {
	if ( is_front_page() ) {
		wp_dequeue_script( 'woocommerce' );
		wp_dequeue_script( 'wc-add-to-cart' );
		wp_dequeue_script( 'wc-cart-fragments' );
		wp_dequeue_script( 'storefront-header-cart' );
	}
}
add_action( 'wp_print_scripts', 'prefix_remove_scripts', 100 );

To dequeue styles you can use the wp_enqueue_scripts hook:

/**
 * Remove styles that have been enqueued by other plugins.
 */
function prefix_remove_styles() {
	if ( is_front_page() ) {
		wp_dequeue_style( 'wp-block-library' );
		wp_dequeue_style( 'wc-block-vendors-style' );
		wp_dequeue_style( 'wc-block-style' );
		wp_dequeue_style( 'woocommerce-inline' );
	}
}
add_action( 'wp_enqueue_scripts', 'prefix_remove_styles', 100 );

I’ve limited the dequeues to the front page of the site in these code blocks, but you can use different page conditionals to remove the scripts and styles from where they are not needed.

You can include this code directly in the functions.php file of your theme, but I generally load a separate file as a class either from a mu-plugin or the theme. Here’s what that type of file might look like.

WooCommerce Performance: Indexing the post_modified_gmt column

WooCommerce 5.8 added support for modified_before and modified_after params when querying to the REST API for products, orders and coupons in the in the REST API endpoints. Here’s the PR that was merged.

This is great as lots of external services use the REST API to fetch data, and this allows them to just fetch data that has changed since the last sync.

However, if you have a really large posts table (~1 million records and up), this type of query may be slower than you’d like as post_modified and post_modified_gmt are not indexed columns in the database.

Continue reading

WooCommerce Performance: Using post_author to store order customer IDs

WooCommerce stores order records in the posts table as a shop_order post type. The majority of data associated with the order, such as the order_total or billing and shipping information is stored in the postmeta table.

This works fine in most cases, but once a WooCommerce shop scales past ~1 million orders, queries of postmeta can start to run long. If WordPress needs to get a specific customer’s orders (such as in the customer account dashboard), it requires a querying against _customer_user key in the postmeta table.

Continue reading

WP CLI Scripts and WooCommerce

If you manage a WooCommerce store, you’ll like need to bulk update or modify a large number of orders, subscriptions, products or customer records at some point. Writing a WP CLI script can be a quick and easy way to do this.

In this video I show how to export products into a CSV using WP CLI and the command wp eval-file, but the general concepts can be used to loop over any resource you may want to export, modify or delete.

Continue reading

Managing Fraud Orders in WooCommerce

One morning I woke up to find 20,000 new fraudulent orders on a WooCommerce site I manage. The vast majority of them were in failed status, but a few had successfully completed. We quickly determined this was a card testing attack, where a fraudster was using an automated system to iterate through a huge amount of stolen credit card numbers to check out on our site and determine which ones were still valid.

The biggest concern with this type of attack is that your credit card processor may stop processing payments from your site altogether due to fraud concerns, which means the business is dead until you can find a new payment processor.

As soon as we noticed the fraud, we alerted our payment processor and let them know we were taking steps to stop the attack and refund the fraudulent orders- which I think was helpful for keeping our account in good status.

Continue reading

How to Avoid Excess Meta with WooCommerce Subscriptions

Orders in WooCommerce create a lot data in the postmeta table. There’s the standard WooCommerce fields (like _order_key, _cart_hash, _billing_first_name, etc.), but payment gateway plugins, marketing integrations, and other WooCommerce plugins also generate their own metadata. It’s not unusual to see more than 60 rows of metadata for each order.

I recommend the Post Meta Inspector to easily view all the metadata on any order or post. You may be surprised how much there is!

If you run subscriptions on your site and generate a lot of renewals, WooCommerce Subscriptions may be creating a lot of unneeded metadata due to how subscriptions and renewal orders are generated. This can cause your database to grow really quickly.

Continue reading

Update the Modified Date in a WooCommerce Order

If you run a script to update order properties in WooCommerce, you may want to update the “post_modified” date along with the other updates. Many third-party integrations rely on the post_modified date to sync any order changes or updates.

Here’s how you can easily update the modified date (assuming you have the order object):

$order->set_date_modified( time() );

Here’s a full example which fetches the order, updates the date, and saves the order.

$order = wc_get_order( 123 );
$order->set_date_modified( time() );
$order->save();

Example Cart Restrictions in WooCommerce

I’ve been working with a “Trial Product” in a WooCommerce store which needs to be the only item in the cart during checkout due to shipping requirements (and because it doesn’t make sense to order a trial if you’re also going to order the actual product).

To make this clear to the customer, I’ve restricted what can be added to the cart in specific situations:

1) If the “Trial Product” is already in the cart, additional products should not be added. WooCommerce will instead display a notice asking the customer to remove the “Trial Product” from their cart if they wish to add different products.

2) If products are already in the cart, and the customer attempts to add the “Trial Product”, a notice will display asking the customer to remove the other items from their cart first.

Continue reading