Few weeks ago I have tested 35 plugins to find how they affect WordPress in terms of loading and resource usage. What can plugin author do to make plugin loading faster, to use less memory and to lower its impact on website loading? There are several things to consider.
Notice: This tutorial is primarily for plugin developers, but it can be useful reading for anyone working with WordPress to better understand how plugins load and what can be done to improve it.
Before we go on, I recommend you to take a look at the article with test results. I know that many readers were surprised by the results, considering how some high-profile plugins scored very low and ended up in the bad optimized plugins category. Optimization will take these plugins one step further, showing that author cares about used resources (most WordPress websites are on shared hosting, and resources can be very limited), and that author understands that optimization is as important as adding features and making plugin look pretty.
So, what plugin authors can do to make their plugins better, how to optimize their loading, resource usage and with that speed? Before I list recommendations for this, here is a small analysis of how plugins are loaded.
One of the early steps in the WordPress loading is to load plugins. WordPress will get the list of all active plugins and it simply use PHP include function to load main plugin file. That main plugin file can contain the plugin (for smaller plugins or widgets), or it can be used as plugin loader to initialize plugin, or it can be the mix of the two. WordPress will do this for every single page, it will always include active plugins.
Even if the plugin is small, this can be an issue. For instance, my GD Unit Converter plugin was used in the benchmark article. This plugin adds a widget on the admin dashboard, and that’s it. But, if you look at test results it was using 0.5MB on admin side and 0.4MB on the front end side. And it was doing nothing on front end side! So, I changed the main plugin file to act as a loader only. It will check if we are on admin side, and it will load another file that actually contains plugin. If we are on front end side, it will do nothing. After this optimization, on front end side plugin uses now 20KB, that is 95% memory saved. That is amazing gain, but you can’t expect such results for every plugin.
If you look at the test results again, even smallest plugins will use 0.4MB to 0.5MB. Imagine that you have 20 such plugins, and if all 20 of them save just 0.2MB, that will lower memory usage by 4MB, and will improve speed a bit. That might not look like a lot, but trust me, it will make a difference, especially for shared hosting websites.
Most plugins have a specific usage, and that requires plugin to be loaded only on some pages. In some cases you will need parts of the plugin functionalities loaded on every page. It can be very complicated to decide the need for plugin on each admin or front end page. But, you need to recognize what parts of the plugin are always needed, and what parts will be specific to some of the pages. That basic analysis will help you to decide what pieces of code go into separate files. If your plugin is only for the administration, it doesn’t need to be loaded on the front end. It is very simple to check this in the loader file and to prevent loading of the rest of the plugin.
Files and folders organization
- Code should be split into files according to functionalities. Many plugins don’t have that strict code separation, and they end up with large files with functions and classes thrown in. This makes later changes and maintenance harder, because code has no logical structure or order. Also, big files will use more memory, even if most of its functionality will not be used at all.
- HTML forms should be separated from files with code. These forms will be loaded only on some pages, and they will contain mostly HTML markup code (they can contain PHP code, and usually do, but only used to fill HTML elements with data), and they should be kept outside of the main plugin code.
Preparing for Optimization
To make the most of the loading process, you need to know what page are you on. Based on that you can perform different operation and load different files. Make sure you set a variable with the page file name or some other identification. On admin side, WordPress pages are identified by the file name loaded. Your own plugin pages can be identified by the ‘page’ variable from the URL request . To get the name of the file, name of the page and more, you can use this code:
$_current_file = end(explode("/", $_SERVER["PHP_SELF"])); $_current_page = isset($_GET["page"]) ? $_GET["page"] : ""; $_doing_ajax = defined("DOING_AJAX") && DOING_AJAX; $_doing_cron = defined("DOING_CRON") && DOING_CRON;
Based on this values you can pretty much know exactly which page is loaded, and what you need from your plugin to load. This can be executed in the main/loader plugin file. I have added two more variables to determine if the page is loaded for AJAX handling or while doing Cron job.
Here are some of the important recommendations you should follow:
- Analyze your plugin code, and decide what you need loaded on admin side, what on front end, and what on both. When you do that, you can go further and decide what you need loaded on all admin pages, and what on some of them (your plugin panels). Based on that, you will end up with many smaller files. Make some convenient naming scheme so that you can easily find files and use them in loader.
- Always use main plugin file as loader. Even for simple plugins, this is best solution because you will have easier time later to expand the plugin. Don’t keep any code that is used by the plugin there, only decide what parts of the plugin you need to load.
- Try to use classes as much as you can. Also, try to have only one class in a file, or at least put classes that depend on each other in one file. Use some logical naming convention for files, so that name gives you quick association to the class inside. PHP can help you with auto loading of files based on the required class, and you can find more info on that at the end of this tutorial.
- Separate all AJAX handling code into own file. When your plugin on the server-side needs to handle AJAX requests, don’t add all that into file that is always loaded. It is easy to decide if the WordPress is loading to handle AJAX request, and only then load AJAX handling file. This goes only if the AJAX is handled by the WordPress admin-ajax.php file.
- Always handle all AJAX calls through WordPress admin-ajax.php. This will save you a lot of headaches, and it can be used for both front end and admin side. Making your own handler file for AJAX is never good idea. If you need help with using admin-ajax.php, here is a good post in the WordPress.org Codex on using AJAX in plugins.
- Separate all Cron jobs handling code into own file. Similar to AJAX handling, Cron jobs executions are run in own page/thread call, and you can always determine if that is the case. If you have cron jobs in your plugin, move all its handling functions and classes into files that will be loaded only when Cron job is executed.
- Any other code elements that are needed for some panels only, or in some specific cases, keep in own file(s) and load them only when needed. This can be code that handles individual panels, AJAX handling, CRON handling, saving data… The better you identify what you need and make smaller files to load when needed, you will get better optimized files.
- Handle all plugin settings through WordPress options database table through get_option/update_option functions (or get_site_option/update_site_option for multisite network wide settings). Never save individual settings as separate options, this can create a mess and will be hard to update and maintain. Put all your settings in one or more array’s (depending on the scope of settings you have). These settings are all loaded with a single SQL query when WordPress loads, and you have them ready when your plugin loads.
PHP Auto Loading
PHP has several methods to trigger automatic loading of files, based on the required code. If you split your code into classes, you can set up autoload functions that will do loading of files based on the class name. This can be very good solution for a plugin that has many classes used as modules, or used only in some cases. It is recommended to have one class in one file. More info about this you can find here: Autoloading Classes on PHP.net. Comments on that page have some really great examples on how the auto loading works.
Measuring the optimization
My GD Press Tools Pro plugin can be used to debug and track WordPress loading. Tracker in this plugin has functions you can use to create snapshots that will contain used memory, hooks, SQL queries and time. You can use these functions in your code to measure how much resources some are used during different stages in the loading process. Plugin has a lot of other things to help you debug the code, find errors, track loading, track WordPress query, enqueued scripts and styles and much more.
There are some other plugins you can use to debug WordPress, but no other plugin allows tracking of the loading and the level of detail as GD Press Tools has.
There are many things you can do to optimize your plugin to use less memory and to load faster, and to have less impact on overall loading of WordPress. This article doesn’t cover everything and you will not be able to use all the recommendations for every plugin. But, good analysis, good code splitting and loading and tracking your optimization progress will always give you good results. Better optimized plugin is later easier to support and expand.