Search and Replace
Powerful search and replace functionality for WordPress content and database
Search and Replace
Master powerful search and replace operations in WordPress. Learn to safely modify content, update URLs, and perform bulk database operations with confidence.
Search and Replace Overview
What is Search and Replace?
Search and replace functionality allows you to find and modify text, URLs, or data across your entire WordPress site. This is essential for:
- Domain Migrations: Update all URLs when moving domains
- Content Updates: Bulk modify text across posts and pages
- Database Cleanup: Fix broken links or update references
- Content Migration: Update content from other systems
- SEO Optimization: Update meta descriptions or keywords
Types of Search and Replace
Content Search and Replace
- Post Content: Text within posts and pages
- Post Meta: Custom fields and metadata
- Comments: Comment content and author information
- User Data: User profiles and information
Database Search and Replace
- Serialized Data: PHP serialized arrays and objects
- JSON Data: JSON-encoded database fields
- HTML Content: HTML markup and attributes
- URLs and Links: Internal and external links
Using WordPress Built-in Tools
WP-CLI Search and Replace
Basic Search and Replace
# Basic text replacement
wp search-replace 'old-text' 'new-text'
# Replace in specific tables
wp search-replace 'old-text' 'new-text' --table=wp_posts
# Multiple replacements
wp search-replace 'old-text' 'new-text' 'another-old' 'another-new'URL Updates
# Update site URL
wp search-replace 'https://old-domain.com' 'https://new-domain.com'
# Update with dry run first
wp search-replace 'https://old-domain.com' 'https://new-domain.com' --dry-run
# Update specific post types
wp search-replace 'https://old-domain.com' 'https://new-domain.com' --post_type=pageDatabase-Specific Operations
# Replace in post content only
wp search-replace 'old-text' 'new-text' --include-columns=post_content
# Skip certain tables
wp search-replace 'old-text' 'new-text' --skip-tables=wp_users
# Case-insensitive search
wp search-replace 'OLD-TEXT' 'new-text' --case-insensitiveAdmin Dashboard Tools
Using Plugins
Better Search Replace Plugin
// Programmatic usage
function bulk_search_replace($search, $replace, $tables = array()) {
global $wpdb;
if (empty($tables)) {
$tables = array(
'wp_posts',
'wp_postmeta',
'wp_options',
'wp_comments'
);
}
foreach ($tables as $table) {
$sql = $wpdb->prepare(
"UPDATE {$table} SET column_content = REPLACE(column_content, %s, %s)",
$search,
$replace
);
$wpdb->query($sql);
}
return $wpdb->rows_affected;
}Search & Replace Plugin Features
- Dry Run Mode: Preview changes before applying
- Backup Creation: Automatic backup before changes
- Selective Tables: Choose specific database tables
- Regex Support: Regular expression search patterns
- Export Results: Export replacement results
Advanced Search and Replace Techniques
Regular Expression Search
Basic Regex Patterns
# Find email addresses
wp search-replace '/[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}/' 'contact@example.com'
# Find phone numbers
wp search-replace '/\b\d{3}[-.]?\d{3}[-.]?\d{4}\b/' '(555) 123-4567'
# Find URLs with specific patterns
wp search-replace '/https?:\/\/(www\.)?old-domain\.com/' 'https://new-domain.com'Complex Pattern Matching
# Replace old shortcode syntax
wp search-replace '\[old_shortcode([^\]]*)\]' '[new_shortcode$1]'
# Update image paths
wp search-replace '/wp-content\/uploads\/(\d{4})\/(\d{2})\//' '/wp-content/uploads/$1/$2/'
# Fix broken internal links
wp search-replace 'href="/old-path"' 'href="/new-path"'Serialized Data Handling
PHP Serialized Arrays
// Handle serialized data carefully
function search_replace_serialized($search, $replace, $data) {
// Unserialize if needed
if (is_serialized($data)) {
$unserialized = unserialize($data);
// Perform replacement on unserialized data
if (is_array($unserialized)) {
array_walk_recursive($unserialized, function(&$value) use ($search, $replace) {
if (is_string($value)) {
$value = str_replace($search, $replace, $value);
}
});
} elseif (is_string($unserialized)) {
$unserialized = str_replace($search, $replace, $unserialized);
}
// Re-serialize
return serialize($unserialized);
}
// Regular string replacement
return str_replace($search, $replace, $data);
}WordPress Options Table
# Update site options
wp option update siteurl 'https://new-domain.com'
wp option update home 'https://new-domain.com'
# Update theme options
wp option patch update my_theme_options '{"logo_url":"https://new-domain.com/logo.png"}'Custom Field Operations
ACF Fields
// Update Advanced Custom Fields
function update_acf_fields($search, $replace, $field_name) {
$posts = get_posts(array(
'post_type' => 'any',
'meta_key' => $field_name,
'posts_per_page' => -1
));
foreach ($posts as $post) {
$current_value = get_field($field_name, $post->ID);
if (is_string($current_value)) {
$new_value = str_replace($search, $replace, $current_value);
update_field($field_name, $new_value, $post->ID);
} elseif (is_array($current_value)) {
// Handle array fields
array_walk_recursive($current_value, function(&$value) use ($search, $replace) {
if (is_string($value)) {
$value = str_replace($search, $replace, $value);
}
});
update_field($field_name, $current_value, $post->ID);
}
}
}Bulk Content Operations
Post Content Updates
Update All Posts
function bulk_update_post_content($search, $replace, $post_type = 'post') {
$args = array(
'post_type' => $post_type,
'posts_per_page' => -1,
'post_status' => 'any'
);
$posts = get_posts($args);
foreach ($posts as $post) {
$updated_content = str_replace($search, $replace, $post->post_content);
$updated_excerpt = str_replace($search, $replace, $post->post_excerpt);
wp_update_post(array(
'ID' => $post->ID,
'post_content' => $updated_content,
'post_excerpt' => $updated_excerpt
));
}
return count($posts);
}Update Post Meta
function bulk_update_post_meta($meta_key, $search, $replace) {
global $wpdb;
$sql = $wpdb->prepare(
"UPDATE {$wpdb->postmeta} SET meta_value = REPLACE(meta_value, %s, %s) WHERE meta_key = %s",
$search,
$replace,
$meta_key
);
return $wpdb->query($sql);
}User Data Updates
Update User Profiles
function bulk_update_user_data($search, $replace, $field = 'description') {
$users = get_users(array('fields' => 'all'));
foreach ($users as $user) {
$current_value = get_user_meta($user->ID, $field, true);
if (!empty($current_value)) {
$new_value = str_replace($search, $replace, $current_value);
update_user_meta($user->ID, $field, $new_value);
}
}
return count($users);
}Safe Search and Replace Practices
Backup First
# Create full backup before operations
wp db export backup-before-search-replace.sql
tar -czf content-backup.tar.gz wp-content/
# Verify backup integrity
wp db checkDry Run Testing
# Always test with dry run first
wp search-replace 'old-text' 'new-text' --dry-run
# Check what would be changed
wp search-replace 'old-text' 'new-text' --dry-run | head -20Selective Operations
// Target specific content types
function selective_search_replace($search, $replace, $conditions = array()) {
$args = array(
'post_type' => $conditions['post_type'] ?? 'any',
'post_status' => $conditions['post_status'] ?? 'publish',
'date_query' => $conditions['date_query'] ?? null,
'posts_per_page' => -1
);
$posts = get_posts($args);
foreach ($posts as $post) {
// Apply conditions
if (isset($conditions['has_shortcode'])) {
if (!has_shortcode($post->post_content, $conditions['has_shortcode'])) {
continue;
}
}
// Perform replacement
$updated_content = str_replace($search, $replace, $post->post_content);
wp_update_post(array(
'ID' => $post->ID,
'post_content' => $updated_content
));
}
return count($posts);
}Performance Considerations
Large Site Optimization
Batch Processing
function batch_search_replace($search, $replace, $batch_size = 100) {
$args = array(
'post_type' => 'any',
'posts_per_page' => $batch_size,
'offset' => 0
);
$total_processed = 0;
do {
$posts = get_posts($args);
if (empty($posts)) break;
foreach ($posts as $post) {
$updated_content = str_replace($search, $replace, $post->post_content);
wp_update_post(array(
'ID' => $post->ID,
'post_content' => $updated_content
));
}
$total_processed += count($posts);
$args['offset'] += $batch_size;
// Prevent timeout
if ($total_processed % 1000 === 0) {
sleep(1);
}
} while (!empty($posts));
return $total_processed;
}Memory Management
// Increase memory limit for large operations
ini_set('memory_limit', '512M');
// Process in chunks to avoid memory issues
function memory_safe_search_replace($search, $replace) {
global $wpdb;
$chunk_size = 1000;
$offset = 0;
do {
$posts = $wpdb->get_results($wpdb->prepare(
"SELECT ID, post_content FROM {$wpdb->posts} LIMIT %d OFFSET %d",
$chunk_size,
$offset
));
if (empty($posts)) break;
foreach ($posts as $post) {
$updated_content = str_replace($search, $replace, $post->post_content);
$wpdb->update(
$wpdb->posts,
array('post_content' => $updated_content),
array('ID' => $post->ID)
);
}
$offset += $chunk_size;
// Free memory
unset($posts);
if (function_exists('gc_collect_cycles')) {
gc_collect_cycles();
}
} while (true);
return $offset;
}Error Handling and Rollback
Transaction-Based Operations
function transactional_search_replace($search, $replace, $table, $column) {
global $wpdb;
// Start transaction
$wpdb->query('START TRANSACTION');
try {
// Create backup
$backup_table = $table . '_backup_' . time();
$wpdb->query("CREATE TABLE {$backup_table} AS SELECT * FROM {$table}");
// Perform replacement
$sql = $wpdb->prepare(
"UPDATE {$table} SET {$column} = REPLACE({$column}, %s, %s)",
$search,
$replace
);
$result = $wpdb->query($sql);
if ($result === false) {
throw new Exception('Search and replace failed');
}
// Commit transaction
$wpdb->query('COMMIT');
return array(
'success' => true,
'rows_affected' => $result,
'backup_table' => $backup_table
);
} catch (Exception $e) {
// Rollback on error
$wpdb->query('ROLLBACK');
return array(
'success' => false,
'error' => $e->getMessage()
);
}
}Rollback Procedures
function rollback_search_replace($backup_table, $original_table) {
global $wpdb;
// Restore from backup
$wpdb->query("DROP TABLE IF EXISTS {$original_table}");
$wpdb->query("RENAME TABLE {$backup_table} TO {$original_table}");
return $wpdb->last_error ? false : true;
}Advanced Use Cases
Content Migration from Other Systems
Import from CSV
function import_and_replace_from_csv($csv_file, $search_replace_map) {
$imported = 0;
$errors = array();
if (($handle = fopen($csv_file, 'r')) !== false) {
$headers = fgetcsv($handle); // Skip header
while (($data = fgetcsv($handle)) !== false) {
$post_data = array_combine($headers, $data);
// Apply search/replace mappings
foreach ($search_replace_map as $search => $replace) {
$post_data['content'] = str_replace($search, $replace, $post_data['content']);
}
// Create post
$post_id = wp_insert_post(array(
'post_title' => $post_data['title'],
'post_content' => $post_data['content'],
'post_status' => 'publish',
'post_type' => 'post'
));
if (is_wp_error($post_id)) {
$errors[] = $post_id->get_error_message();
} else {
$imported++;
}
}
fclose($handle);
}
return array('imported' => $imported, 'errors' => $errors);
}Multilingual Content Updates
function multilingual_search_replace($search, $replacements) {
// Handle different languages
$current_lang = get_locale();
if (isset($replacements[$current_lang])) {
$replace = $replacements[$current_lang];
return str_replace($search, $replace, get_the_content());
}
return get_the_content();
}Monitoring and Logging
Operation Logging
function log_search_replace_operation($operation_data) {
$log_entry = array(
'timestamp' => current_time('mysql'),
'user_id' => get_current_user_id(),
'operation_type' => 'search_replace',
'search_term' => $operation_data['search'],
'replace_term' => $operation_data['replace'],
'tables_affected' => $operation_data['tables'],
'rows_affected' => $operation_data['rows_affected'],
'backup_created' => $operation_data['backup_created']
);
// Store in custom table
global $wpdb;
$wpdb->insert('wp_search_replace_logs', $log_entry);
return $wpdb->insert_id;
}Best Practices
Pre-Operation Checklist
- Create full database backup
- Test operations on staging environment
- Use dry-run mode to preview changes
- Document all changes and reasoning
- Have rollback plan ready
- Notify stakeholders of planned changes
During Operation
- Work in small batches for large sites
- Monitor server resources and performance
- Log all operations for audit trail
- Verify changes immediately after operation
- Test site functionality after changes
Post-Operation
- Clear all caches (page, object, CDN)
- Test search functionality and navigation
- Check for broken links or images
- Update XML sitemaps if URLs changed
- Monitor site performance and errors
Safety Measures
- Always Backup First: Never perform operations without backup
- Test on Staging: Always test on staging environment first
- Use Dry Run: Preview changes before applying
- Work in Batches: Process large datasets in manageable chunks
- Monitor Performance: Watch for performance impact during operations
- Have Rollback Plan: Be prepared to revert changes if needed
Master powerful search and replace operations for WordPress content management.