Table Prefixes
WordPress uses configurable table prefixes for security and multi-installation support.
Default Prefix
// wp-config.php
$table_prefix = 'wp_';
All core tables will be named wp_posts, wp_users, etc.
Why Use Custom Prefixes
Security Through Obscurity
$table_prefix = 'mysite_';
Makes automated SQL injection attacks slightly harder (they often target wp_ tables directly).
Multiple Installations
// Site 1 wp-config.php
$table_prefix = 'site1_';
// Site 2 wp-config.php
$table_prefix = 'site2_';
Allows multiple WordPress installations in one database.
Best Practices
- Use alphanumeric characters and underscores only
- Keep it short but unique
- End with underscore for readability
- Set before installation (changing later is complex)
Accessing Table Names in Code
Using $wpdb
global $wpdb;
// Core tables (use properties, not hardcoded names)
$wpdb->posts // wp_posts
$wpdb->postmeta // wp_postmeta
$wpdb->users // wp_users
$wpdb->usermeta // wp_usermeta
$wpdb->comments // wp_comments
$wpdb->commentmeta // wp_commentmeta
$wpdb->terms // wp_terms
$wpdb->termmeta // wp_termmeta
$wpdb->term_taxonomy // wp_term_taxonomy
$wpdb->term_relationships // wp_term_relationships
$wpdb->options // wp_options
$wpdb->links // wp_links
// Current prefix
$wpdb->prefix // "wp_" (or custom)
// For custom tables
$custom_table = $wpdb->prefix . 'my_custom_table';
Never Hardcode Table Names
// BAD - breaks with custom prefixes
$wpdb->get_results( "SELECT * FROM wp_posts" );
// GOOD - uses dynamic prefix
$wpdb->get_results( "SELECT * FROM {$wpdb->posts}" );
// GOOD - custom table with prefix
$wpdb->get_results(
"SELECT * FROM {$wpdb->prefix}my_custom_table"
);
Multisite Prefixes
Base vs Site Prefix
global $wpdb;
// Base prefix (network tables)
$wpdb->base_prefix; // "wp_"
// Site prefix (per-site tables)
$wpdb->prefix; // "wp_" (main site) or "wp_2_" (site 2)
// Get prefix for specific site
$wpdb->get_blog_prefix( 2 ); // "wp_2_"
$wpdb->get_blog_prefix( 1 ); // "wp_"
Network vs Site Tables
// Network tables (always base_prefix)
$wpdb->blogs // wp_blogs
$wpdb->site // wp_site
$wpdb->sitemeta // wp_sitemeta
$wpdb->signups // wp_signups
$wpdb->registration_log // wp_registration_log
// User tables (shared, base_prefix)
$wpdb->users // wp_users
$wpdb->usermeta // wp_usermeta
// Site tables (use current prefix)
$wpdb->posts // wp_posts or wp_2_posts
$wpdb->options // wp_options or wp_2_options
Changing Prefix After Installation
Not recommended but possible:
- Export database
- Update
$table_prefixin wp-config.php - Rename all tables
- Update
wp_options.option_namereferences - Update
wp_usermeta.meta_keyreferences
SQL to Rename Tables
-- Generate rename statements
SELECT CONCAT(
'RENAME TABLE `', table_name, '` TO `newprefix_',
SUBSTRING(table_name, 4), '`;'
)
FROM information_schema.tables
WHERE table_schema = 'your_database'
AND table_name LIKE 'wp_%';
Update Option References
-- Update options table references
UPDATE newprefix_options
SET option_name = REPLACE(option_name, 'wp_', 'newprefix_')
WHERE option_name LIKE 'wp_%';
-- Update user meta references
UPDATE newprefix_usermeta
SET meta_key = REPLACE(meta_key, 'wp_', 'newprefix_')
WHERE meta_key LIKE 'wp_%';
Prefix in Queries
Prepared Statements
$wpdb->prepare(
"SELECT * FROM {$wpdb->posts} WHERE ID = %d",
$post_id
);
Complex Joins
$sql = $wpdb->prepare(
"SELECT p.*, pm.meta_value
FROM {$wpdb->posts} p
LEFT JOIN {$wpdb->postmeta} pm
ON p.ID = pm.post_id AND pm.meta_key = %s
WHERE p.post_type = %s",
'_thumbnail_id',
'post'
);
Prefix Validation
Valid prefix characters:
- Letters (a-z, A-Z)
- Numbers (0-9)
- Underscore (_)
// WordPress validates prefix during install
if ( preg_match( '|[^a-z0-9_]|i', $prefix ) ) {
// Invalid prefix
}
Common Issues
Plugin Hardcoding
Some poorly-written plugins hardcode wp_ prefix. These break with custom prefixes.
Export/Import
When migrating, update prefixes in:
- SQL dump files
- Serialized data (use proper search-replace tools)
PHPMyAdmin
Remember your actual prefix when browsing tables.