Skip to main content
Blog|
Learning center

WordPress index.php and wp-admin Files: What They Do

|
Mar 18, 2026|11 min read
LEARNING CENTERWordPress index.php andwp-admin Files: What They DoHOSTNEYhostney.comMarch 18, 2026

WordPress is a PHP application. When a visitor loads a page on your site, they are not loading a static HTML file. They are triggering a chain of PHP files that query a database, assemble content, and generate the HTML that the browser renders. Understanding which files do what helps when something breaks, when you are reading error logs, or when you see unfamiliar filenames consuming server resources.

This guide explains the key PHP files in a WordPress installation: what each one does, when it runs, and the common problems associated with each.

The WordPress request lifecycle#

Before looking at individual files, it helps to understand the sequence that happens on every page load.

  1. The web server (Nginx or Apache) receives a request
  2. If no static file matches the URL, the server passes the request to  index.php
  3. index.php  loads  wp-blog-header.php
  4. wp-blog-header.php  loads  wp-load.php , which loads  wp-config.php
  5. wp-config.php  defines database credentials and constants, then loads  wp-settings.php
  6. wp-settings.php  initializes WordPress: loads the database layer, loads active plugins, loads the active theme, sets up the query
  7. WordPress parses the URL, runs the main database query, and hands the result to the theme
  8. The theme generates the HTML output
  9. The response is sent back to the browser

Every front-end page load follows this path. The entire sequence runs inside a single PHP process and typically completes in under a second on a properly configured server.

index.php#

index.php is the entry point for every front-end request. It sits in the WordPress root directory and contains almost no code:

<?php
define('WP_USE_THEMES', true);
require __DIR__ . '/wp-blog-header.php';

That is the entire file. It sets a flag telling WordPress to use themes (as opposed to running headlessly), then loads the bootstrap file that starts the WordPress initialization sequence.

Why index.php matters

When Nginx serves a WordPress site, the configuration typically includes a try_files directive:

try_files $uri $uri/ /index.php?$args;

This tells Nginx: try to serve the URL as a static file first. If no file exists, pass the request to index.php . This is how pretty permalinks work. A URL like /blog/my-post/ does not correspond to a file on disk. Nginx finds no matching file, falls back to index.php , and WordPress’s routing system figures out which content to serve.

If index.php is missing or corrupted, every page on your site breaks. If the try_files directive does not include the index.php fallback, all WordPress URLs except the homepage return a 404. See How to fix 404 errors in Nginx for the full troubleshooting process.

index.php in subdirectories

You will also find index.php files inside wp-admin/ and wp-content/ . The wp-admin/index.php is the entry point for the WordPress dashboard. The wp-content/index.php is typically an empty file that exists only to prevent directory listing – if someone navigates to /wp-content/ in a browser, the empty index.php stops the web server from showing a list of all your plugin and theme directories.

wp-config.php#

wp-config.php is the main configuration file. It sits in the WordPress root directory (or one level above it, which WordPress checks automatically). This file is not part of WordPress core – it is generated during installation and is unique to your site.

It contains:

Database credentials:

define('DB_NAME', 'wordpress');
define('DB_USER', 'wp_user');
define('DB_PASSWORD', 'your_password');
define('DB_HOST', 'localhost');

Authentication keys and salts:

define('AUTH_KEY', 'unique-random-string');
define('SECURE_AUTH_KEY', 'unique-random-string');
// ... more keys

These keys encrypt the cookies that keep you logged in. If they are changed, every logged-in user is logged out immediately.

Table prefix:

$table_prefix = 'wp_';

Debug settings:

define('WP_DEBUG', false);

See How to display PHP errors and enable error reporting for the full explanation of WP_DEBUG , WP_DEBUG_LOG , and WP_DEBUG_DISPLAY .

Common wp-config.php issues

White screen of death. A syntax error in wp-config.php stops WordPress from loading entirely. You see a blank page with no error message because PHP cannot get far enough to display one. If you recently edited wp-config.php and your site went blank, check for missing semicolons, unclosed quotes, or typos in constant names.

Database connection error. The “Error establishing a database connection” message almost always traces back to wp-config.php. Either the credentials are wrong, the database host is incorrect, or the database server is down.

File permissions. wp-config.php contains your database password. Its permissions should be 600 (owner read/write only) or 640 (owner read/write, group read). Never 644 or 755.

setup-config.php#

setup-config.php lives in wp-admin/ and is the file that runs during a fresh WordPress installation. When you see the “Welcome to WordPress” screen asking for database credentials, you are looking at setup-config.php.

The full URL is:

https://example.com/wp-admin/setup-config.php

When you see setup-config.php

You encounter this file in two situations:

Fresh installation. You have uploaded WordPress files to a server but have not created wp-config.php yet. WordPress detects the missing config file and redirects to setup-config.php, which walks you through entering database credentials and generates the file.

Deleted or corrupted wp-config.php. If wp-config.php is removed, renamed, or contains a syntax error severe enough that PHP cannot parse it, WordPress falls back to the setup screen. On a live site, this is alarming because it means anyone who visits can re-run the installer. If you see setup-config.php on a site that was previously working, check that wp-config.php exists and is readable by PHP.

Security note

On a running site, setup-config.php should never be accessible. Once WordPress is installed, it serves no purpose. Some security hardening guides recommend deleting it, but this is unnecessary if wp-config.php exists – WordPress will never route to setup-config.php when the config file is present. The real risk is if wp-config.php is accidentally deleted or moved during a migration or cleanup.

wp-login.php#

wp-login.php handles authentication. It is the login form at /wp-login.php , the logout action, the password reset flow, and the registration form (if registration is enabled).

This file is the most attacked endpoint on any WordPress site. Automated bots probe it constantly with credential stuffing attacks, trying leaked username and password combinations from data breaches. See What happens when bots find your WordPress login page for what this looks like from the server side and why it degrades performance.

Why wp-login.php is expensive

Every login attempt, successful or not, requires a full PHP execution cycle and at least one database query. Password hashing is deliberately computationally expensive (this is a security feature). Under a credential stuffing attack with hundreds of attempts per minute, wp-login.php can consume more PHP-FPM workers than your actual visitors, potentially leading to 503 errors.

Protecting wp-login.php

The effective protections are server-level, not plugin-level:

  • Rate limiting at the web server. Nginx can limit requests to wp-login.php per IP before they reach PHP.
  • IP-based access control. Restrict wp-login.php to known IPs if your team works from fixed locations.
  • Bot detection. Server-level bot detection that identifies and blocks attack traffic before it reaches WordPress.

admin-ajax.php#

admin-ajax.php lives in wp-admin/ and is the endpoint WordPress uses for AJAX requests. Despite the “admin” in its name, it handles AJAX calls from both the admin dashboard and the front end of the site.

The URL is:

https://example.com/wp-admin/admin-ajax.php

How admin-ajax.php works

When a plugin or theme needs to make an asynchronous request (load more posts, update a cart, check for notifications, submit a form without a page reload), it sends a POST request to admin-ajax.php with an action parameter that identifies which handler to run.

POST /wp-admin/admin-ajax.php
action=load_more_posts&page=2

WordPress receives the request, loads the full WordPress stack (yes, the entire thing), finds the registered handler for that action, runs it, and returns the response. Each AJAX call is a complete PHP execution.

Why admin-ajax.php becomes a problem

admin-ajax.php is the single most common source of excessive PHP load on WordPress sites, for several reasons:

Every call loads the entire WordPress stack. There is no lightweight path. A simple AJAX request to check if a notification exists loads the same PHP files as a full page render. On a site with many plugins, this initialization alone can take 100-300ms.

Plugins add front-end AJAX calls without restraint. A plugin that checks for updates, a live chat widget polling for messages, a WooCommerce cart fragment that refreshes on every page load, a notification plugin checking for alerts. Each one fires an AJAX request to admin-ajax.php. A site with five such plugins generates five AJAX requests per page view, per visitor.

It is not cacheable. Because admin-ajax.php is a POST endpoint and the response depends on the request payload, page caching does not help. Every AJAX request hits PHP-FPM. On a site with 1,000 daily visitors and three AJAX calls per page view, that is 3,000 additional PHP executions per day that bypass your cache entirely.

WooCommerce cart fragments. WooCommerce uses admin-ajax.php to update the cart widget on every page load. The AJAX call sends a POST to admin-ajax.php?action=wc_ajax_get_refreshed_fragments . On a high-traffic store, this single feature can generate more PHP load than all the actual page views combined. WooCommerce provides a setting to disable cart fragments on pages where the cart widget is not displayed.

Diagnosing admin-ajax.php load

If your server is slow and you are not sure why, check your access logs for admin-ajax.php:

grep admin-ajax.php /var/log/nginx/access.log | wc -l

If this returns a number significantly higher than your actual page view count, plugins are generating excessive AJAX traffic.

To identify which plugin is responsible, check the action parameter in the requests:

grep admin-ajax.php /var/log/nginx/access.log | grep -oP 'action=\K[^& ]+' | sort | uniq -c | sort -rn | head -20

This shows which AJAX actions are called most frequently. The action name usually maps directly to a specific plugin.

Reducing admin-ajax.php load

Disable WooCommerce cart fragments on pages that do not display the cart. Several plugins provide this (Disable Cart Fragments, or the setting in optimization plugins like Perfmatters).

Audit plugin AJAX usage. Deactivate plugins one at a time and check if AJAX traffic drops. Some plugins make AJAX calls on every page load even when their functionality is only needed on specific pages.

Use the REST API instead. Modern WordPress development favors the REST API ( /wp-json/ ) over admin-ajax.php. The REST API can be more efficient because endpoints can be designed to load only the code they need, unlike admin-ajax.php which loads the full WordPress stack every time. If you are developing custom functionality, use the REST API.

wp-cron.php#

wp-cron.php is WordPress’s built-in task scheduler. It handles scheduled events like publishing future-dated posts, checking for plugin updates, sending scheduled emails, and running maintenance tasks.

How wp-cron.php works

WordPress does not use the server’s cron system by default. Instead, on every page load, WordPress checks if any scheduled tasks are due. If they are, it fires an asynchronous HTTP request to wp-cron.php to run them. This means:

  • On a low-traffic site, scheduled tasks may run late because nobody visited to trigger the check
  • On a high-traffic site, wp-cron.php adds an extra PHP execution on many page loads
  • If a scheduled task is slow (like sending emails or running a backup), it ties up a PHP worker

Replacing wp-cron.php with a real cron job

The standard recommendation is to disable WordPress’s web-triggered cron and replace it with a server-level cron job. Add to wp-config.php:

define('DISABLE_WP_CRON', true);

Then add a system cron job:

*/5 * * * * cd /var/www/html && wp cron event run --due-now

This runs scheduled tasks every 5 minutes via WP-CLI, regardless of traffic. It eliminates the extra PHP execution on page loads and ensures tasks run on time even on low-traffic sites.

xmlrpc.php#

xmlrpc.php is the XML-RPC interface. It was designed to allow external applications to communicate with WordPress, including posting from desktop clients, pingbacks, and remote management.

Why xmlrpc.php is a problem

XML-RPC is largely obsolete. The WordPress REST API provides the same functionality with better security and more granular authentication. But xmlrpc.php still exists in every WordPress installation and is enabled by default.

Attackers use it for:

  • Brute force amplification. The  system.multicall  method allows testing hundreds of password combinations in a single HTTP request. Rate limiting that restricts wp-login.php to a few attempts per minute does not apply to xmlrpc.php.
  • DDoS amplification via pingbacks. The pingback feature can be abused to make your server send HTTP requests to a target, turning your site into a participant in a DDoS attack.

If you do not use desktop publishing clients or apps that require XML-RPC (most people do not), disable it. The simplest method is blocking it at the web server level so requests never reach PHP.

Common issues by file#

FileCommon problemLikely cause
index.php All pages return 404Missing try_files directive in Nginx, or index.php deleted
wp-config.php White screen / database errorSyntax error in config, wrong DB credentials
setup-config.php Install screen on live sitewp-config.php missing or unreadable
wp-login.php Site slow, high CPUBot credential stuffing attack
admin-ajax.php High server load, slow pagesPlugins generating excessive AJAX requests
wp-cron.php Scheduled tasks late or slowLow traffic (cron not triggered) or slow tasks blocking workers
xmlrpc.php Brute force attacks, abuseXML-RPC enabled and not blocked at server level

WordPress files on Hostney#

On Hostney, WordPress runs inside an isolated container per account. The web server (Nginx) and PHP-FPM are configured automatically with the correct try_files directive, proper permissions, and optimized settings.

Hostney’s bot detection system blocks credential stuffing attacks against wp-login.php and xmlrpc.php at the server level before they reach PHP, so your PHP workers are not consumed by bot traffic.

PHP configuration including memory limits, error reporting, and execution timeouts is adjustable through Hosting > PHP Manager in the control panel. Error logs and access logs are available under Logs & Statistics for diagnosing issues with any of the files covered in this guide. See the access and error logs knowledge base page for details.