How to Customize a WordPress Plugin Without Losing Changes on Update
A plugin almost does what you need, so someone opens its PHP files and changes a few lines. It works perfectly, until the next update wipes those changes out. Or worse, nobody dares update the plugin for two years, and it becomes the security hole that gets the site hacked. Here's how to customize a plugin so updates stay safe, from the cleanest option to the last resort.
Inherited a site where plugins were already edited? Don't update anything yet. First download a fresh copy of the same version from WordPress.org (or the vendor) and compare it with the live plugin folder to see exactly what was changed. A diff tool like diff -r original/ live/ or WinMerge makes this quick. Then move each change into one of the approaches below.
Option 1: Use the plugin's hooks
Well-written plugins are full of actions (points where you can run your own code) and filters (points where you can change a value before the plugin uses it). Using them means your code lives outside the plugin and survives every update.
Search the plugin for hooks near the behavior you want to change:
grep -rn "apply_filters\|do_action" wp-content/plugins/the-plugin/ | grep -i "price"
Say you find this in the plugin:
$label = apply_filters( 'the_plugin_button_label', __( 'Add to quote', 'the-plugin' ), $product );
Then you can change the label without touching the plugin:
add_filter( 'the_plugin_button_label', function ( $label, $product ) {
return 'Request a price';
}, 10, 2 );
The last two arguments are the priority (10 is the default) and how many arguments your function accepts. It must match what the plugin passes, or you'll only receive the first value.
Where to put that code: a must-use plugin
Not in the theme's functions.php, because changing the theme would silently remove your plugin fixes. The better place is a must-use plugin: a PHP file in wp-content/mu-plugins/ that WordPress always loads and that can't be deactivated by accident.
<?php
/**
* Plugin Name: Site Customizations
* Description: Update-safe tweaks to third-party plugins. See README in this folder.
*/
// Rename the quote button (the-plugin v3.x).
add_filter( 'the_plugin_button_label', function ( $label, $product ) {
return 'Request a price';
}, 10, 2 );
Save it as wp-content/mu-plugins/site-customizations.php (create the folder if it doesn't exist). Add a comment next to each customization saying which plugin and version it targets. Whoever maintains the site next will thank you.
Option 2: Remove or replace the plugin's own output
Plugins add their output with add_action(), so you can take it out with remove_action() and add your own version. WooCommerce is a good example. This moves the product meta (SKU, categories) above the price:
add_action( 'init', function () {
remove_action( 'woocommerce_single_product_summary', 'woocommerce_template_single_meta', 40 );
add_action( 'woocommerce_single_product_summary', 'woocommerce_template_single_meta', 8 );
} );
Two details trip people up:
- The priority must match exactly. If the plugin added it at 40, removing it at 10 does nothing, and you get no error message.
- Timing matters. You can't remove an action before the plugin has added it, which is why the code above runs on
initrather than immediately.
When the plugin hooks a method on an object, you need that same object instance. Many plugins expose it through a function or a static instance() method:
add_action( 'plugins_loaded', function () {
if ( function_exists( 'the_plugin' ) ) {
remove_action( 'wp_footer', array( the_plugin(), 'render_badge' ), 20 );
}
}, 20 );
Option 3: Override templates the supported way
WooCommerce and many plugins built on the same pattern (LearnDash, The Events Calendar, Easy Digital Downloads and others) let you override their template files from your theme. For WooCommerce:
- Find the template in
wp-content/plugins/woocommerce/templates/, e.g.single-product/price.php. - Copy it to
wp-content/themes/your-child-theme/woocommerce/single-product/price.php, keeping the same folder structure. - Edit your copy. WooCommerce now uses it instead of the original.
Check WooCommerce → Status after each WooCommerce update. Under "Templates" it lists overrides that are out of date compared to the plugin's new version. Copy the new version and re-apply your changes, ideally keeping the change small and well commented.
Option 4: Change the front end with CSS or JavaScript
For purely visual changes, override the plugin's styles in your child theme or the Customizer's Additional CSS. To stop a plugin's assets loading on pages that don't need them:
add_action( 'wp_enqueue_scripts', function () {
if ( ! is_page( 'contact' ) ) {
wp_dequeue_style( 'the-plugin-style' );
wp_dequeue_script( 'the-plugin-script' );
}
}, 100 );
The handle names (the-plugin-style) come from the plugin's wp_enqueue_style() calls, or from the Query Monitor plugin's "Scripts" and "Styles" panels.
Option 5 (last resort): Fork the plugin properly
Sometimes there's no hook, the plugin is abandoned, or the change is too deep. Then stop pretending it's the original plugin:
- Rename the plugin folder and change the
Plugin Nameheader, e.g. "The Plugin (Site Fork)". - Add
Update URI: falseto the plugin header. Since WordPress 5.8, this stops WordPress from offering updates from WordPress.org for it, so nobody can overwrite your fork by accident. - Put the fork in Git and write down why it exists and what changed.
- Check the original plugin's security advisories regularly. You're now responsible for patching it.
/**
* Plugin Name: The Plugin (Site Fork)
* Version: 3.2.1-site.1
* Update URI: false
*/
For developer-managed sites built with Composer, an alternative is keeping the original plugin and applying your change as a patch file with cweagans/composer-patches. Updates then fail loudly if the patch no longer applies, instead of silently dropping your change.
One more option: ask for a hook
If a plugin you rely on is actively maintained, open a support request asking for a filter at the spot you need. Many developers add one in the next release, and then your customization becomes a two-line filter.
Written by
Sameer Hussain, Senior Shopify & WordPress Engineer
Top Rated on Upwork and the Shopify & WordPress engineer at Inceptus Digital. Short on time, or not comfortable editing code? Send me your URL and the error on Upwork and I'll tell you how I'd fix it before you commit.
Need Custom Engineering or Growth Systems?
Our team helps ambitious brands build bespoke software, AI integrations, and high-conversion platforms.