Question

How to Create a Directory If It Does Not Exist in PHP and WordPress

phpwordpressdirectory

Question

In a WordPress theme, how can I check whether the wp-content/uploads directory exists and create it if it does not?

I have seen some WordPress installations, especially on Bluehost, where my theme throws errors because the uploads folder is missing. It appears that some installers do not create wp-content/uploads automatically.

I want to add code to my theme that:

  • checks whether the uploads folder exists
  • creates it if it is missing
  • avoids errors when the folder is already present

Short Answer

By the end of this page, you will understand how to check whether a directory exists in PHP, how to create it safely, and how to do this the WordPress-friendly way. You will also learn when this logic belongs in a theme, what common mistakes to avoid, and how developers usually handle filesystem setup in real projects.

Concept

In PHP, directories are just filesystem paths. Before writing files into a directory, your code should verify that the directory exists. If it does not, you can create it with functions such as mkdir().

In WordPress, this matters because themes and plugins often need a safe place to store uploaded images, generated files, cached assets, or exported data. If your code assumes a folder exists and it does not, file operations like copy(), move_uploaded_file(), or image generation will fail.

For the specific case of wp-content/uploads, WordPress already has built-in ways to work with the uploads directory. That is important because:

  • the uploads path may be filtered or customized
  • WordPress can create the directory structure for you
  • using WordPress functions makes your code more portable

The core idea is simple:

  1. Determine the correct path
  2. Check whether it exists
  3. Create it only if needed
  4. Handle failure safely

In plain PHP, that usually means is_dir() plus mkdir(). In WordPress, it is usually better to use wp_upload_dir() and, when needed, wp_mkdir_p().

A beginner-friendly rule is:

  • use PHP filesystem functions to understand the concept
  • use WordPress helper functions inside WordPress projects whenever possible

Mental Model

Think of a directory like a storage cabinet in an office.

  • is_dir() asks: Does this cabinet already exist?
  • mkdir() says: Build a new cabinet here
  • WordPress helper functions are like asking the building manager where the correct cabinet should go instead of guessing the room yourself

If you try to put files into a cabinet that does not exist, the action fails. So the safe workflow is always:

  • check first
  • create if missing
  • then save the file
Take Quiz

Syntax and Examples

In plain PHP, the basic pattern looks like this:

$path = __DIR__ . '/uploads';

if (!is_dir($path)) {
    mkdir($path, 0755, true);
}

What each part means

  • is_dir($path) checks whether the path exists and is a directory
  • mkdir($path, 0755, true) creates the directory
  • 0755 is a common permission mode on Unix-like systems
  • true allows recursive creation, meaning parent folders can also be created if missing

WordPress-friendly version

For WordPress, do not hardcode wp-content/uploads if you can avoid it. Use wp_upload_dir():

$upload_info = wp_upload_dir();
$upload_dir = $upload_info['basedir'];

if (!is_dir($upload_dir)) {
    wp_mkdir_p($upload_dir);
}

Why this is better in WordPress

wp_upload_dir() gives you the correct uploads base directory for the current site. This is safer than assuming the folder is always exactly wp-content/uploads.

Example inside a theme or plugin

function mytheme_ensure_upload_dir_exists() {
    $upload_info = wp_upload_dir();

    if (!empty($upload_info['error'])) {
        return;
    }

    $upload_dir = $upload_info['basedir'];

    if (!is_dir($upload_dir)) {
        wp_mkdir_p($upload_dir);
    }
}

This function:

  • asks WordPress for the uploads directory
  • stops if WordPress reports an error
  • checks whether the folder exists
  • creates it if necessary

Step by Step Execution

Consider this example:

$upload_info = wp_upload_dir();
$upload_dir = $upload_info['basedir'];

if (!is_dir($upload_dir)) {
    wp_mkdir_p($upload_dir);
}

Here is what happens step by step:

  1. wp_upload_dir() runs.

    • WordPress calculates the correct uploads folder.
    • It returns an array with values like path, url, subdir, basedir, and baseurl.
  2. $upload_dir = $upload_info['basedir'];

    • Your code stores the base uploads directory path.
    • Example value: /home/account/public_html/wp-content/uploads
  3. is_dir($upload_dir) runs.

    • PHP checks the filesystem.
    • If the directory exists, this returns true.
    • If it does not exist, this returns false.
  4. if (!is_dir($upload_dir))

    • The ! means “not”.
    • So the code inside the block runs only when the directory is missing.
  5. wp_mkdir_p($upload_dir) runs.

    • WordPress attempts to create the folder.
    • It can create nested directories if needed.
  6. After that, later code can safely write files into the uploads directory.

Small trace example

Suppose:

  • $upload_dir is /var/www/site/wp-content/uploads
  • that folder does not exist

Then:

  • is_dir($upload_dir) returns false
  • !false becomes true
  • wp_mkdir_p($upload_dir) executes
  • the folder is created

If the folder already exists:

  • is_dir($upload_dir) returns true
  • !true becomes false
  • creation is skipped

Real World Use Cases

Checking for and creating directories is common in real applications.

In WordPress

  • ensuring the uploads folder exists before generating thumbnails
  • creating a custom export folder for CSV or JSON files
  • preparing a cache directory for generated assets
  • storing plugin-generated backups or reports

In general PHP applications

  • creating a log directory before writing log files
  • creating a user-specific folder for uploaded documents
  • preparing storage for image processing output
  • creating nested directories for date-based archives

Example: custom theme export folder

$upload_info = wp_upload_dir();
$export_dir = $upload_info['basedir'] . '/exports';

if (!is_dir($export_dir)) {
    wp_mkdir_p($export_dir);
}

This is useful if your theme or plugin generates downloadable files.

Take Quiz

Real Codebase Usage

In real projects, developers usually do more than just call mkdir().

1. They avoid hardcoded paths

Instead of assuming the uploads location, they ask WordPress:

$upload_info = wp_upload_dir();
$base_dir = $upload_info['basedir'];

2. They use guard clauses

A guard clause exits early if setup data is invalid.

$upload_info = wp_upload_dir();

if (!empty($upload_info['error'])) {
    return;
}

This keeps the rest of the code simpler.

3. They create app-specific subfolders

Rather than writing directly into the root uploads folder, code often creates a dedicated subdirectory.

$dir = $upload_info['basedir'] . '/mytheme';

if (!is_dir($dir)) {
    wp_mkdir_p($dir);
}

4. They check return values

Directory creation can fail because of permissions, wrong paths, or hosting restrictions.

if (!is_dir($dir) && !wp_mkdir_p($dir)) {
    error_log('Could not create directory: ' . $dir);
    return;
}

5. They place setup logic in the right location

Common places include:

  • plugin activation hooks
  • admin setup routines
  • file upload handlers
  • lazy creation right before first file write

For themes, avoid heavy setup on every page load if possible. A function that runs only when needed is usually better.

6. They prefer dedicated subfolders over touching global folders unnecessarily

Creating uploads/mytheme is often cleaner than managing the entire uploads root manually.

Common Mistakes

Here are common beginner mistakes and how to avoid them.

Mistake 1: Hardcoding the uploads path

Broken approach:

$dir = ABSPATH . 'wp-content/uploads';

Why this is risky:

  • uploads location can be customized
  • multisite and filters can change paths

Better:

$upload_info = wp_upload_dir();
$dir = $upload_info['basedir'];

Mistake 2: Using file_exists() when you specifically want a directory

This works in some cases, but it is less precise:

if (!file_exists($dir)) {
    mkdir($dir);
}

Better:

if (!is_dir($dir)) {
    mkdir($dir);
}

file_exists() returns true for both files and directories. is_dir() clearly expresses your intent.

Mistake 3: Ignoring permissions errors

Broken approach:

mkdir($dir);

If it fails, your code may continue as if everything worked.

Better:

if (!is_dir($dir) && !wp_mkdir_p($dir)) {
    error_log('Directory creation failed: ' . $dir);
    return;
}

Mistake 4: Creating directories on every request without need

Repeated checks are usually cheap, but filesystem setup does not always belong in front-end theme rendering.

Better approaches:

  • create the directory when the feature is first used
  • create it during setup or activation when possible
  • keep the check in a small reusable function

Mistake 5: Forgetting recursive creation

Broken approach:

mkdir('/path/to/uploads/mytheme/reports');

This can fail if mytheme does not exist.

Better:

mkdir('/path/to/uploads/mytheme/reports', 0755, true);

Or in WordPress:

wp_mkdir_p('/path/to/uploads/mytheme/reports');

Mistake 6: Putting writable data inside the theme folder

Themes can be updated or replaced. Generated files should usually go into uploads, not inside the theme directory.

Comparisons

ApproachBest forProsCons
is_dir() + mkdir()Plain PHP projectsSimple, built into PHPYou must handle WordPress path details yourself
file_exists() + mkdir()General path existence checksWorks for files or foldersLess precise when you specifically need a directory
wp_upload_dir() + wp_mkdir_p()WordPress projectsUses WordPress paths, safer and more portableRequires WordPress context

is_dir() vs file_exists()

FunctionChecks forUse when
is_dir($path)A directoryYou need to know whether a folder exists
file_exists($path)A file or directoryYou only care whether something exists at that path

mkdir() vs wp_mkdir_p()

FunctionRecursive?WordPress-aware?Notes
mkdir()Only if you pass true as third argumentNoStandard PHP function
wp_mkdir_p()YesYes, for WordPress usage patternsConvenient in WordPress code

Theme vs plugin placement

LocationGood choice?Why
Theme template fileUsually noRuns during page rendering and mixes setup with output
Theme function used when neededBetterKeeps logic centralized
Plugin activation or feature setupOften bestMore predictable for setup tasks
Take Quiz

Cheat Sheet

// Plain PHP
$dir = __DIR__ . '/uploads';
if (!is_dir($dir)) {
    mkdir($dir, 0755, true);
}

// WordPress
$upload_info = wp_upload_dir();
$dir = $upload_info['basedir'];
if (!is_dir($dir)) {
    wp_mkdir_p($dir);
}

Quick rules

  • Use is_dir() when checking for a folder
  • Use mkdir($path, 0755, true) in plain PHP
  • Use wp_upload_dir() to get the uploads path in WordPress
  • Use wp_mkdir_p() in WordPress for recursive directory creation
  • Check for errors from wp_upload_dir() when appropriate
  • Do not store generated writable files inside a theme folder

Safe WordPress pattern

$upload_info = wp_upload_dir();

if (!empty($upload_info['error'])) {
    return;
}

$dir = $upload_info['basedir'] . '/mytheme';

if (!is_dir($dir) && !wp_mkdir_p($dir)) {
    error_log('Failed to create directory: ' . $dir);
    return;
}

Edge cases

  • path exists but is a file, not a directory
  • web server does not have write permission
  • uploads path is customized
  • code runs too early before WordPress is fully loaded

FAQ

Should I use mkdir() or wp_mkdir_p() in WordPress?

Use wp_mkdir_p() when writing WordPress code. It fits WordPress projects better and handles recursive directory creation cleanly.

Is it safe to hardcode wp-content/uploads?

It is better not to. WordPress can use a different uploads path, so wp_upload_dir() is safer.

What is the difference between is_dir() and file_exists()?

is_dir() checks specifically for a folder. file_exists() checks whether any filesystem item exists at that path.

Where should I put this logic in a theme?

Put it in a reusable function and run it only when needed, such as before saving a file. Avoid scattering it across template files.

What if directory creation fails?

Usually the cause is permissions or an invalid path. Check the return value, log the failure, and avoid continuing as if the directory exists.

Should I create the root uploads folder or a custom subfolder?

Usually you should ask WordPress for the uploads base directory, then create your own subfolder if your theme or plugin needs one.

Can this code run on every request?

It can, but that is not always ideal. It is usually better to run it only when the related feature is actually used.

Take Quiz

Mini Project

Description

Build a small WordPress utility function that ensures a theme-specific uploads folder exists before your code writes files into it. This mirrors a real use case: a theme needs a reliable writable directory for generated assets, exports, or cached images.

Goal

Create a reusable function that finds the WordPress uploads directory, creates a mytheme subfolder if needed, and returns the final path safely.

Requirements

  • Get the uploads base directory using a WordPress function
  • Stop early if WordPress reports an uploads error
  • Create a mytheme subfolder only if it does not already exist
  • Return the final directory path when successful
  • Return false if creation fails
Take Quiz

Keep learning

Related questions

View more