Learn how to disable plugins except for specified urls. Inspired by Plugin Organizer plugin, I disabled CF7 for all but the contact page.
A client contacted me last week reporting that their site was very slow to load. I went to the site and confirmed that it wasn’t just very slow, it was very, very, very slow – it took about 12 seconds to load!! After the first page was loaded it was noticeably quicker, but still quite sluggish.
The site is on shared hosting and the theme is a child of Twenty Twelve. I added the site to my Uptime Robot dashboard and it reported a time for first response of 11 seconds. I submitted a support ticket to the hosting company. They replied overnight to saying that there was nothing up with server.
The following day the load time had reduced considerably, though still about 4 seconds. I suspect that there was a temporary issue on the server e.g. another site gone wild.
I installed P3 (Plugin Performance Profiler) and it reported that Polylang was responsible for 65% of the page load time, followed by Contact Form 7 at 21%. Polylang could not be deactivated as it is required to present the site in three languages (English, French and German). Contact Form 7 is only used on three pages so the site would be okay if it was deactivated except for those pages.
I searched for suggestions to conditionally disable CF7 but the solutions all involved changing the pages that the CF7 assets (CSS and JS files) were loaded. I tried this but it made only a negligible difference – I was going to have to disable the entire plugin!
I found the Plugin Organizer plugin and tried it out. Despite a slightly strange interface (mostly a styling thing), I was able to globally disable the CF7 plugin and selectively enable on the pages with the CF7 forms. The site load time was further reduced.
While I wasn’t concerned that I added a plugin to disable another, I felt that I should be able to write code to do the same thing.
Plugin Organizer copies a file (lib/PluginOrganizerMU.class.php) into the wp-content/mu-plugins directory. I read through the code and saw its approach – filter the list of active plugins listed in the ‘active_plugins‘ option.
I did some debugging experiments with the ‘option_active_plugins‘ filter, sending data to the debug.log file. I saw that the CF7 plugin was listed as ‘contact-form-7/wp-contact-form-7.php‘ in the option.
My next decision was to decide whether to examine the active plugins first or the current url. I felt that examining the plugins would make for an easier data structure: plugin => array of urls.
The code goes through the list of active plugins. If a plugin is in the $disable_plugins list, it checks whether the requested url is in that plugin’s exclusion list. If not, it adds the plugin to a list of plugins to disable.
If any plugins need to be disabled it uses array_diff() to remove them from the list of active plugins (Plugin Organizer used array_diff – I’m constantly learning new array manipulation functions).
It is very simple code and the site’s load time is now about 600ms (according to P3), and about 1300ms according to Uptime Robot.
Note: This plugin must be installed in the wp-content/mu-plugins directory. It would run too late if activated like a regular plugin. The code is generic so you can add different plugins and urls.
need to have contact form enabled for ‘/wp-json/contact-form-7/’ url, otherwise messages are not sent
R: Good point. On one or two sites I disable REST API and had to exclude the contact-form-7 routes. In the code above you can add that route to the array: ` ‘contact-form-7/wp-contact-form-7.php’ => array( ‘/wp-json/contact-form-7/’, ‘/contact-us/’, ‘/contact-us-fr/’, ‘/kontakt/’ ),`
If you haven’t already, can you please try it and let me know if it works. If it does then I will update the code and add a comment explaining why the url is included.
R confirmed that ‘/wp-json/contact-form-7’ is needed to allow the plugin to send messages. Thanks for checking. I have updated the gist.
Bob T. Builder says
You should cache your $new_list and return that if it’s set, because the option_active_plugins hook may be fired multiple times.
Good point. I rarely write PHP classes but this is a good reason to do so. Thanks for the suggestion. I’ll add it to my todo list.
Almost what im looking for.
I need a conditional that willl disable a plugin by part of a url. Is this even possible in theory?
@Peter – The newer version of this code uses a PHP class to allow for urls that *start* with those in the $disable_plugins array. This allows for Contact Form 7 REST API endpoints. It uses strpos() instead of array_search(). The code is at https://www.damiencarbery.com/2019/03/class-to-disable-wordpress-plugins-by-url/
For your needs you could change ‘0 === strpos()’ to ‘false !== strpos()’ as that will mean that the exception url is found anywhere in the actual url.
That did the trick :)
Brilliant – happy to help.
David Elstob says
Cool idea, Daimien.
Why not use WP Forms instead of CF7, as it only loads on form pages anyway?
Pingdom gives me a warning for the Google analytics collection pixel having a no cache policy. I’m struggling to disable CAOS conditionally for Pingdom, have tried several tricks to no avail.
Would be awesome if I could utilize your plugin to help me pass this error.
@David: I only heard about WP Forms recently and, after doing lots of coding for Ninja Forms, I’m very reluctant to move to another form plugin.
It sounds like you are sort of trying to “fake” your Pingdom results. Does that defeat the purpose of the results? Or am I missing the point?
David Elstob says
@Damien: Sorry, I thought the email replies posted here also.
The result would be ‘real’ but indirectly ‘fake’, as you point out.
However, I’ve noticed people turn off analytics just to pass this test. I was hoping replicating the idea from FVM would do the trick. Turns out that all I had to do was ‘defer’ the analytics tracking script rather than ‘async’.
It’s probably why FVM offer defer on PSI only.
So I’ve found a ‘real’ solution in the end. :)