Every WordPress hardening checklist tells you to put DISALLOW_FILE_EDIT in wp-config.php, and about half of them describe it as if it locks your filesystem against attackers. It does not. DISALLOW_FILE_EDIT only turns off the built-in code editor screens for themes and plugins in wp-admin; an administrator can still upload a malicious plugin ZIP three clicks later and run whatever PHP they like. The constant that actually stops plugin installs, theme installs and dashboard updates is DISALLOW_FILE_MODS — and turning that one on without understanding the side effects will silently stop your automatic security updates too.
The short answer, if that is all you came for
define( 'DISALLOW_FILE_EDIT', true ); on almost every production site: it removes the edit_files, edit_plugins and edit_themes capabilities so nobody can edit PHP live in a browser textarea. Only set define( 'DISALLOW_FILE_MODS', true ); when every core, plugin, theme and translation update is deployed from Git or CI — because it blocks all dashboard installs and updates, including background core security updates.DISALLOW_FILE_EDIT vs DISALLOW_FILE_MODS: side by side
Both constants live in wp-config.php and both are checked inside map_meta_cap() in wp-includes/capabilities.php. When either constant is truthy, WordPress maps a set of file-related capabilities to do_not_allow for every user on the site, including Super Admins on Multisite.
| Action in WordPress | Default (neither set) | DISALLOW_FILE_EDIT = true | DISALLOW_FILE_MODS = true |
|---|---|---|---|
Edit plugin or theme PHP files in wp-admin (edit_plugins, edit_themes, edit_files) | Allowed for Administrators | Blocked | Blocked (implies file edit block) |
Install or upload a new plugin or theme ZIP (install_plugins, install_themes) | Allowed for Administrators | Allowed | Blocked |
Update plugins, themes or core from the dashboard (update_plugins, update_themes, update_core) | Allowed for Administrators | Allowed | Blocked |
Delete an inactive plugin or theme (delete_plugins, delete_themes) | Allowed for Administrators | Allowed | Blocked |
Activate or deactivate an already-installed plugin (activate_plugins) | Allowed for Administrators | Allowed | Allowed |
Edit block templates and global styles in the Site Editor (edit_theme_options) | Allowed for Administrators | Allowed (stored in the database, not theme files) | Allowed |
| Automatic background core, plugin, theme and language updates | Runs normally | Runs normally | Blocked via wp_is_file_mod_allowed() |
Media Library uploads (upload_files) | Allowed for Authors and above | Allowed | Allowed |
map_meta_cap() and wp_is_file_mod_allowed() in WordPress core.Read the second row carefully. With DISALLOW_FILE_EDIT set to true, the Tools → Theme File Editor and Tools → Plugin File Editor menu items disappear, and direct requests to theme-editor.php or plugin-editor.php die with a permissions message. Everything under Plugins → Add New Plugin, including the Upload Plugin button, still works as normal.
What DISALLOW_FILE_EDIT actually protects you from
If an attacker with a stolen administrator session can still upload a two-line plugin ZIP under DISALLOW_FILE_EDIT, why bother setting it at all? Three reasons, and the most useful one has nothing to do with hackers.
Understand that boundary before evaluating security plugins that advertise “one-click file editor hardening” as a headline feature. All they are doing is writing that one line into wp-config.php or filtering map_meta_cap at runtime — comparing WooCommerce security plugins separates those checkbox features from controls that actually stop an intrusion.
What DISALLOW_FILE_MODS stops — and what it quietly breaks
DISALLOW_FILE_MODS is a completely different commitment. In core, wp_is_file_mod_allowed( $context ) returns ! DISALLOW_FILE_MODS before running through the file_mod_allowed filter. Core checks that function in four places that matter every day:
- Capability mapping (
disallow_file_modscontext): removesedit_files,edit_plugins,edit_themes,update_plugins,delete_plugins,install_plugins,upload_plugins,update_themes,delete_themes,install_themes,upload_themes,update_coreandinstall_languages. - Automatic updater (
automatic_updatercontext):WP_Automatic_Updater::is_disabled()returnstrueimmediately when file mods are disallowed. No minor core security release, plugin auto-update or theme auto-update will run in the background. - Language pack updates (
async_upgraderandcan_install_language_packcontexts): translation files cannot be downloaded or updated automatically. - Update notices in wp-admin: because no user has
update_core,update_pluginsorupdate_themes, WordPress hides the update badges and rows across the dashboard for everyone.
The trap that catches unmanaged sites
define( 'DISALLOW_FILE_MODS', true ); into a site that does not have an external deployment pipeline applying updates every week, two things happen at once: background security updates stop running, and the dashboard stops telling you that anything is out of date. When WordPress 7.1.2 patched a critical CVE, a site with DISALLOW_FILE_MODS enabled and no CI job neither applied the patch nor showed a banner in wp-admin. That is the exact same silent-drift failure mode as running a commercial plugin with an expired license key, except you did it to your entire install.How to set and verify both constants safely
Always place the constants in wp-config.php above the /* That's all, stop editing! Happy publishing. */ line. Placing them at the bottom of the file, after require_once ABSPATH . 'wp-settings.php';, is the most common reason they appear to do nothing — by the time wp-settings.php has loaded, core has already defined its defaults.
1. Set the constant with WP-CLI
wp config reads and writes wp-config.php in the right position and uses --raw so true is written as a boolean literal rather than the string 'true':
# Check what is currently defined in wp-config.php
wp config list DISALLOW_FILE_EDIT DISALLOW_FILE_MODS
# Standard production setting: disable the code editors only
wp config set DISALLOW_FILE_EDIT true --raw --type=constant
# Immutable / Git-deployed production setting: block all file modifications
wp config set DISALLOW_FILE_MODS true --raw --type=constant
2. Verify effective capabilities and whether a plugin is overriding you
Checking wp-config.php alone is not enough, because a security plugin or mu-plugin can define the constant earlier or hook into file_mod_allowed and map_meta_cap. Test the actual runtime result for an administrator account (user ID 1 here):
# Evaluate the runtime constants and core helper
wp eval '
printf( "DISALLOW_FILE_EDIT: %s\n", defined("DISALLOW_FILE_EDIT") && DISALLOW_FILE_EDIT ? "true" : "false" );
printf( "DISALLOW_FILE_MODS: %s\n", defined("DISALLOW_FILE_MODS") && DISALLOW_FILE_MODS ? "true" : "false" );
printf( "file_mod_allowed: %s\n", wp_is_file_mod_allowed("disallow_file_mods") ? "true" : "false" );
'
# Confirm what user 1 is actually allowed to do
wp user can 1 edit_plugins # Expect: no (when either constant is true)
wp user can 1 install_plugins # Expect: yes (under DISALLOW_FILE_EDIT), no (under DISALLOW_FILE_MODS)
Note an important quirk when you manage a site with DISALLOW_FILE_MODS enabled from the shell: wp plugin install and wp plugin update run without a logged-in user by default, so WP-CLI can still install and update plugins on the server even when DISALLOW_FILE_MODS is true — provided the OS user running wp has filesystem write permissions. If you pass --user=1 to a command that checks capabilities, or if you check Tools → Site Health, WordPress evaluates the capability layer instead. Using WordPress Site Health to find and fix common problems explains what its background-updates test reports when file modifications are turned off.
3. Allow background security updates while keeping dashboard installs locked
Because wp_is_file_mod_allowed() passes a $context string to the file_mod_allowed filter, you can lock down the dashboard with DISALLOW_FILE_MODS while explicitly exempting the automatic updater in an mu-plugin:
<?php
/**
* Plugin Name: Allow Automatic Updates Under DISALLOW_FILE_MODS
* Description: Blocks dashboard installs and edits, but lets core's background updater run.
*/
add_filter( 'file_mod_allowed', function ( $file_mod_allowed, $context ) {
if ( 'automatic_updater' === $context ) {
return true;
}
return $file_mod_allowed;
}, 10, 2 );
Only use that pattern when the filesystem itself is writable by PHP and your goal is purely to stop human admins from installing plugins on production. If your deployment process rsyncs the wp-content/plugins/ directory from staging or Git with --delete — the workflow covered in pushing staging to live in WordPress without losing orders — any background update written directly to production will be wiped out on your next deploy anyway. Keep updates in one place, not two.
Which setting belongs on which environment
- Standard production site (updated from wp-admin or automatic updates): set
DISALLOW_FILE_EDITtotrue; leaveDISALLOW_FILE_MODSunset orfalse. Pair it with a safe plugin update workflow and disabling XML-RPC properly. - Git-deployed or CI/CD production site: set
DISALLOW_FILE_MODStotrueon production so nobody installs a plugin that is missing from version control. Apply updates on staging, test them, and deploy the files. - Client handoff site where the agency retains maintenance:
DISALLOW_FILE_EDITtotrueis non-negotiable. SetDISALLOW_FILE_MODStotrueonly if you are under contract to run updates on a schedule yourself. - Staging or local development environment: leave
DISALLOW_FILE_MODSoff so you can test upgrades freely, and keepDISALLOW_FILE_EDITon so you are never tempted to edit files somewhere your Git repository cannot see.
If a bad edit or update ever slips through before you lock this down and locks you out of wp-admin, neither constant prevents you from recovering from the shell or SFTP — disabling a WordPress plugin when you cannot access your dashboard and enabling WordPress debugging to read the error log will get you back in within a couple of minutes.
Frequently asked questions
If I set DISALLOW_FILE_MODS to true, do I still need DISALLOW_FILE_EDIT?
No. In map_meta_cap(), edit_files, edit_plugins and edit_themes return do_not_allow if either DISALLOW_FILE_EDIT is true or wp_is_file_mod_allowed( 'disallow_file_mods' ) is false. Setting DISALLOW_FILE_MODS to true automatically disables the file editors too.
Does DISALLOW_FILE_MODS stop users from uploading images to the Media Library?
No. Media uploads are controlled by the upload_files capability and write to wp-content/uploads/. DISALLOW_FILE_MODS only restricts upload_plugins and upload_themes along with code updates and deletions.
Does DISALLOW_FILE_EDIT or DISALLOW_FILE_MODS block the Full Site Editor?
Neither blocks the Site Editor. Editing templates, template parts, patterns and global styles in a block theme checks edit_theme_options and writes to the database (wp_posts), not to PHP or HTML files on disk.
Why is the Plugin File Editor still gone after I removed DISALLOW_FILE_EDIT from wp-config.php?
Either DISALLOW_FILE_MODS is also set to true, a managed host defines DISALLOW_FILE_EDIT in an earlier preload file, or a security plugin is defining the constant or filtering map_meta_cap at runtime. Run wp eval 'var_dump( defined("DISALLOW_FILE_EDIT"), wp_is_file_mod_allowed("disallow_file_mods") );' to see which layer is active.
Can I still activate and deactivate installed plugins when DISALLOW_FILE_MODS is true?
Yes. Activating or deactivating a plugin checks activate_plugins and updates the active_plugins row in wp_options without modifying files on disk, so DISALLOW_FILE_MODS leaves it enabled. You cannot install a new plugin or delete an inactive one from the dashboard while it is set.
Does WP-CLI work when DISALLOW_FILE_MODS is enabled?
Yes. WP-CLI runs directly against the filesystem as your shell user rather than through the capability check that guards the web admin, so wp core update, wp plugin install and wp plugin update still work unless the directory permissions themselves are read-only at the OS level.
Sources
- Editing wp-config.php and Hardening WordPress — official documentation for
DISALLOW_FILE_EDITandDISALLOW_FILE_MODS - wp_is_file_mod_allowed() and file_mod_allowed filter — how WordPress evaluates
DISALLOW_FILE_MODSacross contexts - map_meta_cap() — the exact list of capabilities mapped to
do_not_allowwhen either constant is enabled - WP_Automatic_Updater::is_disabled() — why
DISALLOW_FILE_MODSdisables background updates

Leave a Reply to This Post