Skip to main content
Blog|
Learning center

What is wp-content and what goes in it

|
Apr 2, 2026|10 min read
LEARNING CENTERWhat is wp-content and whatgoes in itHOSTNEYhostney.comApril 2, 2026

Every WordPress installation has a wp-content directory. It is the single most important directory in your WordPress site because it contains everything that makes your site yours – your theme, your plugins, every image you have ever uploaded, and the custom code that differentiates your site from a fresh WordPress install. The rest of WordPress (the files in wp-admin and wp-includes ) is identical across every WordPress installation of the same version. wp-content is what is unique to you.

Understanding what lives in wp-content , why it is structured the way it is, and what you should and should not modify inside it helps with backups, migrations, security, and troubleshooting.

The wp-content directory structure#

A typical wp-content directory looks like this:

wp-content/
    themes/
    plugins/
    uploads/
    mu-plugins/
    upgrade/
    languages/
    debug.log
    index.php
    object-cache.php
    advanced-cache.php

Not all of these exist on every installation. The themes , plugins , and uploads directories are always present. The rest are created by specific features or plugins when needed.

themes/#

Contains every theme installed on your site, whether active or not. Each theme lives in its own subdirectory:

wp-content/themes/
    twentytwentyfive/
    your-theme/
    your-theme-child/

Only one theme is active at a time (set in the wp_options table under the template and stylesheet options). Inactive themes remain on disk and are accessible via Appearance > Themes in the admin dashboard.

Why inactive themes matter

Inactive themes are not harmless. Their PHP files are still on disk and some can be accessed directly via URL. If an inactive theme has a vulnerability, an attacker can exploit it even though it is not the active theme. This is why WordPress security best practice is to delete themes you are not using – not just deactivate them, but remove them entirely.

Keep the active theme, its parent theme (if it is a child theme), and one default theme (Twenty Twenty-Five or similar) as a fallback. Delete everything else. For a deeper discussion of how plugin and theme vulnerabilities are exploited at scale, see Why WordPress plugin vulnerabilities are out of control.

Child themes

A child theme inherits all the functionality of a parent theme and lets you override specific templates, styles, or functions without modifying the parent. The child theme directory contains only the files you have customized. When WordPress looks for a template file, it checks the child theme first and falls back to the parent if the file does not exist in the child.

This matters for updates. When the parent theme updates, your customizations in the child theme are preserved. If you modify the parent theme directly, those changes are overwritten on the next update.

plugins/#

Contains every plugin installed on your site:

wp-content/plugins/
    woocommerce/
    wordfence/
    akismet/
    your-custom-plugin/

Each plugin has its own subdirectory. WordPress loads active plugins during its initialization phase by reading the list of active plugins from the active_plugins option in the database, then including the main plugin file from each active plugin’s directory.

Active vs inactive plugins

Like themes, inactive plugins remain on disk. Deactivating a plugin tells WordPress to stop loading it, but the files are still there. An inactive plugin with a file upload vulnerability can be exploited if the vulnerable file is accessible via a direct URL request. Delete plugins you do not use.

Plugin file structure

A well-structured plugin typically contains:

your-plugin/
    your-plugin.php          (main plugin file with plugin header)
    includes/                 (PHP classes and functions)
    admin/                    (admin-specific code)
    public/                   (front-end code)
    assets/                   (CSS, JavaScript, images)
    languages/                (translation files)
    templates/                (template files)
    readme.txt                (WordPress.org plugin repository metadata)

The main plugin file ( your-plugin.php ) contains a header comment that WordPress reads to identify the plugin:

<?php
/**
 * Plugin Name: Your Plugin
 * Description: What the plugin does
 * Version: 1.0.0
 * Author: Your Name
 */

Without this header, WordPress does not recognize the file as a plugin.

uploads/#

The largest directory in most WordPress installations. Every file uploaded through the WordPress media library ends up here, organized in year/month subdirectories:

wp-content/uploads/
    2024/
        01/
            photo.jpg
            document.pdf
        02/
            banner.png
    2025/
        03/
            product-image.jpg
    2026/
        01/
            hero-image.webp

Year/month organization

WordPress creates a new subdirectory for each year and month. This is the default behavior and can be disabled in Settings > Media by unchecking “Organize my uploads into month- and year-based folders.” Disabling it puts all uploads in the root of the uploads directory, which becomes unmanageable on sites with thousands of files.

What else lives in uploads

Plugins use the uploads directory for their own file storage. You may see directories like:

  • uploads/woocommerce_uploads/  – WooCommerce downloadable product files
  • uploads/gravity_forms/  – Gravity Forms file upload submissions
  • uploads/backups/  – Backup plugin archives (UpdraftPlus, All-in-One WP Migration)
  • uploads/cache/  – Cache files from various plugins
  • uploads/elementor/  – Elementor page builder assets

Security implications

The uploads directory must be writable by PHP so WordPress can save uploaded files. This makes it a target for attackers. If a vulnerability allows arbitrary file upload, the attacker’s malicious PHP file lands in the uploads directory.

PHP files should never exist in the uploads directory during normal operation. WordPress does not create PHP files there. If you find .php files in the uploads directory, they are almost certainly malware. See How to check a website for malware for scanning techniques.

On well-configured servers, Nginx or Apache is configured to deny PHP execution in the uploads directory. This means even if a malicious PHP file is uploaded, the web server refuses to execute it and returns a 403 instead. On Hostney, this restriction is in place by default.

File permissions

The uploads directory needs 755 for directories and 644 for files. The directory must be owned by the user that PHP-FPM runs as, otherwise WordPress cannot write to it. Permission problems in the uploads directory are one of the most common causes of the “The uploaded file could not be moved to wp-content/uploads” error. See The uploaded file could not be moved to wp-content/uploads for the full troubleshooting walkthrough.

mu-plugins/#

Must-use plugins. Unlike regular plugins, must-use plugins are loaded automatically on every page load without needing activation. They cannot be deactivated from the admin dashboard. They do not appear in the regular Plugins list (they have their own “Must-Use” section on the Plugins page).

wp-content/mu-plugins/
    your-mu-plugin.php
    object-cache.php

When to use mu-plugins

  • Functionality that must always run. If you have code that should never be accidentally deactivated (custom authentication logic, security enforcement, performance modifications), put it in mu-plugins.
  • Hosting provider integrations. Hosting platforms often place their integration code here. Caching drop-ins, object cache connectors, and platform-specific functionality typically live in mu-plugins because they need to run regardless of what the site administrator does with the regular plugins.
  • Code that loads before regular plugins. Must-use plugins load before regular plugins in the WordPress initialization sequence. If you need to hook into WordPress before other plugins load, mu-plugins is the place.

Limitations

Must-use plugins do not support subdirectories by default. WordPress only loads PHP files in the root of mu-plugins/ , not in subdirectories. If you need a must-use plugin with multiple files, the root file must include the additional files explicitly.

Must-use plugins are not tracked by WordPress’s automatic update system. You are responsible for updating them manually.

Drop-in files#

Certain PHP files placed directly in wp-content/ (not in a subdirectory) override WordPress’s default behavior. These are called drop-ins:

  • object-cache.php  – Replaces WordPress’s default object cache with a persistent backend (Memcached, Redis). When this file exists, WordPress uses it for all  wp_cache_*  operations instead of its default in-memory-only cache that expires at the end of each request.
  • advanced-cache.php  – Used by page caching plugins to serve cached pages early in the WordPress load process, before most of WordPress has initialized.
  • db.php  – Replaces or extends WordPress’s database class. Used by database debugging tools and custom database handlers.
  • maintenance.php  – Custom maintenance mode page. If this file exists, WordPress displays it instead of the default “Briefly unavailable for scheduled maintenance” message during updates.

Drop-ins are powerful but easy to forget about. If you uninstall a caching plugin but forget to remove its object-cache.php or advanced-cache.php drop-in, the orphaned file can cause errors or unexpected behavior.

upgrade/#

A temporary directory WordPress uses during plugin, theme, and core updates. When you click “Update” on a plugin, WordPress downloads the new version to upgrade/ , extracts it, replaces the old plugin files, then cleans up. Under normal operation, this directory is empty or contains temporary files during an active update.

If an update is interrupted (browser closed, server timeout, PHP crash), files may be left in the upgrade/ directory. They can usually be deleted safely. If updates are failing repeatedly, leftover files in this directory can be one cause.

languages/#

Contains translation files for WordPress core, themes, and plugins:

wp-content/languages/
    de_DE.mo
    de_DE.po
    plugins/
        woocommerce-de_DE.mo
    themes/
        twentytwentyfive-de_DE.mo

.mo files are compiled translation files that WordPress reads at runtime. .po files are human-readable source files used by translators. WordPress downloads these automatically when you install a language pack.

index.php#

A mostly empty file that exists in wp-content/ and many of its subdirectories:

<?php
// Silence is golden.

This prevents directory listing. Without index.php , a web server configured to allow directory listing would display the contents of the directory to anyone who navigates to yourdomain.com/wp-content/ . The file ensures the server has something to serve, which on most configurations results in a blank page or a 403.

What not to modify in wp-content#

Do not edit plugin files directly

If you modify a plugin’s PHP files, your changes are overwritten the next time the plugin updates. If you need to change a plugin’s behavior, use the plugin’s hooks and filters from your theme’s functions.php or a custom plugin. If the plugin does not provide hooks for what you need, contact the developer or find a different plugin.

Do not edit parent theme files directly

Same reason. Theme updates overwrite your changes. Use a child theme to override specific templates and styles.

Do not store sensitive data in uploads

The uploads directory is web-accessible. Anything you put there can potentially be downloaded by anyone who knows (or guesses) the URL. Do not store database backups, configuration files, or any file containing credentials or sensitive data in the uploads directory.

wp-content and backups#

When backing up a WordPress site, wp-content is the critical directory. WordPress core files ( wp-admin/ , wp-includes/ ) can be reinstalled from a fresh download. The database can be exported with wp db export . But wp-content contains your unique files – the theme customizations, plugin configurations, uploaded media, and custom code that cannot be recreated from scratch.

A complete backup includes:

  1. The  wp-content  directory (all of it)
  2. The database
  3. wp-config.php

Everything else can be reinstalled. These three components are what makes your site your site.

wp-content and migrations#

When migrating WordPress to a new host, wp-content transfers in its entirety. The uploads directory is usually the largest part and takes the most time to transfer. For sites with thousands of images, the uploads directory can be multiple gigabytes.

Some files and directories within wp-content do not need to migrate:

  • cache/  directories (regenerated on the new host)
  • upgrade/  (temporary files)
  • Backup plugin archives (move these separately if needed)
  • debug.log  (not needed on the new host)

For the full migration process including file transfer, database import, and URL replacement, see How to migrate WordPress to another hosting provider.

How Hostney handles wp-content#

File permissions. On Hostney, each site runs in its own container where PHP-FPM runs as the account user. File ownership is set correctly during provisioning, and a background process corrects permission drift automatically. The standard WordPress permissions (755 for directories, 644 for files) are maintained without manual intervention.

PHP execution in uploads. Nginx is configured to deny PHP execution in the uploads directory by default. Even if a malicious file is uploaded through a vulnerability, it cannot be executed as PHP.

Malware monitoring. The platform monitors file changes across wp-content in real time. If a file matching a malware signature is created or modified in any directory including plugins, themes, or uploads, it is quarantined automatically and the incident is reported to the control panel.

Backups. Daily backups include the entire wp-content directory, the database, and the configuration. Restoring from backup restores everything to the exact state at the backup time.

Summary#

wp-content is where everything unique to your WordPress site lives. themes/ holds your active and installed themes. plugins/ holds your active and installed plugins. uploads/ holds every file uploaded through the media library. mu-plugins/ holds must-use plugins that load automatically. Drop-in files in the root of wp-content/ override WordPress defaults for caching and database handling.

Delete unused themes and plugins (not just deactivate – delete). Never edit plugin or parent theme files directly. Never store sensitive data in the uploads directory. When backing up, wp-content plus the database plus wp-config.php is the complete set. Everything else in a WordPress installation can be reinstalled.