Learn how to refactor your WordPress plugin for production by removing dead code, modularizing assets, and finalizing your build configuration for distribution.
Previously in this course, we covered Versioning and Release Management to establish a baseline for tracking our plugin's maturity. Now that we have a stable versioning strategy, we must turn our attention to the physical state of the repository. Shipping a codebase that includes test suites, documentation source files, and development-only configuration leads to bloated downloads and potential security risks.
Refactoring for production is about narrowing the scope of your distribution to the absolute minimum required for the plugin to function in the wild.
When you package your plugin, you are creating a contract with the end-user: only ship the code that executes. Everything else—Docker configs, phpunit.xml, .git directories, and unminified source maps—is overhead.
To achieve this, we treat our distribution process as a destructive, one-way transformation. We don't "clean" the development folder; we copy the necessary files into a temporary dist/ directory, perform final optimizations, and zip that directory.
As we discussed in Modern Build Tooling with Vite, your frontend assets should already be transpiled. However, production modularity goes deeper. You must ensure that your PHP autoloader and dependency graph do not pull in development-only packages.
If you are using Composer, your composer.json likely contains require-dev dependencies like phpunit/phpunit or wp-cli/wp-cli. When preparing for distribution, you must run:
Bashcomposer install --no-dev --optimize-autoloader
This command ensures that only production-essential dependencies are present in the vendor/ directory and that the class map is optimized for high-performance lookups.
A robust production build requires a "clean-room" approach. We will add a build.sh script to our project root that handles the orchestration of these tasks.
Bash#!/bin/bash # build.sh - Finalizing the Knowledge Base plugin for distribution # 1. Clean the previous build rm -rf dist/ mkdir dist/ # 2. Copy production-ready files rsync -av --exclude-from='.distignore' . dist/ # 3. Optimize dependencies cd dist/ composer install --no-dev --optimize-autoloader --no-interaction # 4. Finalize assets (assuming Vite) npm install npm run build echo "Build complete in ./dist"
The key here is the .distignore file. Much like .gitignore, this file defines exactly what stays out of your ZIP package.
Create a .distignore file in your root to keep your distribution lightweight:
TEXT.git .github .vscode tests/ phpunit.xml composer.json composer.lock package.json package-lock.json vite.config.js tailwind.config.js src/
Note: If you are shipping your source files for transparency, you might include src/, but for a commercial plugin, you typically only ship the compiled dist/ or assets/ and the transpiled PHP classes.
phpstan or simply search your codebase for var_dump, error_log, and print_r statements. Remove these entirely, or wrap them in a constant check:
PHPif ( defined( 'WP_DEBUG' ) && WP_DEBUG ) { error_log( 'Debug info' ); }
minify: true in your vite.config.js..distignore file and run a test build. Use ls -lh to check the size of your generated ZIP file. If it's over a few megabytes, investigate which folders are sneaking into the package.node_modules: This is the #1 cause of bloated plugins. Ensure node_modules is explicitly ignored in your .distignore and never copied into the build folder./Users/dev/project/..., it will break on production servers. Always use plugin_dir_path( __FILE__ )..map files generated by Vite) expose your original source code. For production, consider disabling them in your build config to protect your intellectual property.Refactoring for production is the final gatekeeper of quality. By utilizing an automated build script and a strict .distignore file, you ensure that your plugin is secure, performant, and free of the "cruft" that accumulates during development. As we've explored in Production Build Pipeline for WordPress Plugins, consistency in this process is what separates a hobbyist plugin from a professional-grade product.
Up next: We will tackle Plugin Lifecycle Management, focusing on robust uninstall scripts to ensure that when a user deletes your plugin, they aren't left with orphaned database tables or stale options.
Learn how to implement Dependency Injection and a service container in WordPress to eliminate global state and build modular, testable plugins.
Read moreLearn how to implement Dependency Injection in WordPress to decouple your plugin components, improve testability, and master professional software architecture.
Refactoring for Distribution
Custom Hooks for React