Himanshu SharmaSoftware engineer
Let’s talk

WordPress · Lesson 2 of 45

How WordPress works behind the scenes

Follow a request through WordPress, from index.php and wp-config.php to the database query and the theme, and learn the main folders and database tables.

12 minGetting startedUpdated 23 October 2026

By the end of this lessonDescribe what happens when a WordPress page is requested, and find your way around the core files, wp-content and the database tables.

The big picture

A WordPress site is made of three parts:

  1. Files: the WordPress core (PHP), plus your themes, plugins and uploads.
  2. A database: MySQL or MariaDB, holding content, settings and users.
  3. A web server with PHP, which runs the code for each request.

When a browser asks for a page, the web server runs WordPress, WordPress reads from the database, and the active theme turns the result into HTML.

Following one request

Suppose someone visits http://localhost:8080/hello-world/, the sample post every new site has. Here is what happens:

  1. The web server cannot find a real file called hello-world, so it passes the request to WordPress's index.php.
  2. index.php loads wp-config.php, which holds the database settings, and then the core (wp-settings.php).
  3. WordPress loads active plugins and then the active theme, letting both attach their code to hooks (covered later in the course).
  4. WordPress parses the URL. Using the permalink settings, it works out that /hello-world/ means "the post whose slug is hello-world".
  5. It runs a database query for that post.
  6. It chooses a template from the theme, following the template hierarchy (a later lesson): for a single post, something like single.html or single.php.
  7. The template outputs HTML, which goes back to the browser.

You can watch the outcome. This request fetches the page and shows only its title and h1 elements:

http
GET /hello-world/
result
Hello world! – My WordPress Site
http
GET /hello-world/
result
Hello world!

The browser tab shows "Hello world! – My WordPress Site": the post title, a separator and the site title, produced by the theme. On each page in this course, the site runs at http://localhost:8080, like the local site you will set up in the next lesson.

The files

A WordPress folder looks like this:

text
wordpress/
├── index.php            the front door for every request
├── wp-config.php        database settings and site-wide constants (yours)
├── wp-login.php         the login screen
├── wp-admin/            the dashboard (core)
├── wp-includes/         the core libraries (core)
└── wp-content/          everything that is yours
    ├── themes/
    ├── plugins/
    └── uploads/         images and files added through the media library

The rule that keeps sites healthy: never edit core files in wp-admin, wp-includes or the root (apart from wp-config.php). Updates replace them, so your changes would vanish, and a mistake there can take the whole site down. Customise WordPress with themes and plugins instead.

wp-config.php is created during installation. Its key lines look like this (with your own values):

php
define( 'DB_NAME', 'wordpress' );
define( 'DB_USER', 'wp_user' );
define( 'DB_PASSWORD', 'a-strong-password' );
define( 'DB_HOST', 'localhost' );
$table_prefix = 'wp_';

It also holds security keys and salts used to protect logins, and optional settings such as WP_DEBUG. Treat it like a password file: never share it or commit it to a public repository.

The database

WordPress creates about a dozen tables. This code, run inside WordPress, lists them with the global $wpdb object you will use later in the course:

php
<?php
global $wpdb;
foreach ( $wpdb->tables() as $name => $table ) {
	echo str_pad( $name, 20 ), $table, "\n";
}
result
users               wp_users
usermeta            wp_usermeta
posts               wp_posts
comments            wp_comments
links               wp_links
options             wp_options
postmeta            wp_postmeta
terms               wp_terms
term_taxonomy       wp_term_taxonomy
term_relationships  wp_term_relationships
termmeta            wp_termmeta
commentmeta         wp_commentmeta

The ones you will meet most:

Table Holds
wp_posts posts, pages, attachments, menus, templates and custom post types, told apart by post_type
wp_postmeta extra fields attached to posts (custom fields)
wp_users, wp_usermeta accounts and their settings
wp_options site settings, from the site title to plugin options
wp_terms, wp_term_taxonomy, wp_term_relationships categories, tags and other taxonomies
wp_comments, wp_commentmeta comments

The wp_ part is the table prefix from wp-config.php. Many sites use a different prefix, so code should never assume wp_; $wpdb knows the real names.

Everything in wp_posts

A surprise for many people: much more than blog posts lives in wp_posts. A fresh site already holds several kinds:

php
<?php
global $wpdb;
$rows = $wpdb->get_results( "SELECT ID, post_type, post_status, post_title FROM {$wpdb->posts} ORDER BY ID" );
foreach ( $rows as $row ) {
	printf( "%d  %-14s %-8s %s\n", $row->ID, $row->post_type, $row->post_status, $row->post_title );
}
result
1  post           publish  Hello world!
2  page           publish  Sample Page
3  page           draft    Privacy Policy
4  wp_navigation  publish  Navigation

A post, a page, a draft privacy policy page, and a navigation menu (wp_navigation). Nobody created that menu by hand: the theme's header contains a Navigation block, and the first time the front end was displayed (the request earlier in this lesson), WordPress created a menu for it automatically. As you add content, images (attachment), templates and reusable patterns (wp_template, wp_block) will appear here too, each with its own post_type.

Settings live in wp_options

Site settings are rows in wp_options. WordPress reads them with get_option():

php
<?php
foreach ( [ 'blogname', 'blogdescription', 'siteurl', 'permalink_structure', 'template', 'posts_per_page' ] as $option ) {
	echo str_pad( $option, 22 ), var_export( get_option( $option ), true ), "\n";
}
result
blogname              'My WordPress Site'
blogdescription       ''
siteurl               'http://localhost:8080'
permalink_structure   '/%postname%/'
template              'twentytwentyfive'
posts_per_page        '10'

template holds the active theme's folder name. When you change a setting in the dashboard, you are changing one of these rows.

Common mistakes

  • Editing core files instead of using a theme or plugin.
  • Sharing or committing wp-config.php with real passwords.
  • Assuming the wp_ prefix in code or SQL.
  • Changing the database by hand when the dashboard or WP-CLI would do it safely.

Exercise

Using the tables above, answer: where is the site title stored, where is a blog post's text stored, and where would an image's file name be recorded?

Show one possible answer

The site title is the blogname row in wp_options. A post's text is the post_content column of its row in wp_posts. An image is an attachment row in wp_posts, and its file path is stored in wp_postmeta under the key _wp_attached_file; the file itself is in wp-content/uploads.

Key points

  • Every front-end request goes through index.php, which loads wp-config.php, the core, plugins and the theme.
  • WordPress turns the URL into a database query, fetches the matching posts, and picks a theme template to show them.
  • Your own work lives in wp-content (themes, plugins, uploads); never edit core files in wp-admin or wp-includes.
  • Content is stored in about a dozen tables such as wp_posts, wp_postmeta, wp_users, wp_options and the taxonomy tables.

Check yourself

1. Which folder holds your themes, plugins and uploaded files?
2. Which file holds the database name, user and password?
3. Which table stores posts, pages and other content items?
4. Why should you never edit files in wp-includes?