Direct SQL, curl, file_put_contents, and mail() bypass WordPress caching, hooks, security filters, and host compatibility. Use WP_Query, wp_remote_get, WP_Filesystem, and wp_mail.
Why This Matters
ensures compatibility with caching layers, managed hosts, security plugins, and multisite
Impact: MEDIUM (ensures compatibility with caching layers, managed hosts, security plugins, and multisite)
WordPress wraps common PHP operations with APIs that add caching, security hooks, host compatibility, and proper error handling. Using raw PHP functions bypasses all of these layers — breaking on managed hosts (WP VIP, Kinsta, Pantheon), evading security plugin filters, and skipping the object cache.
Incorrect (raw PHP functions):
// ❌ Direct SQL instead of WP_Query — bypasses caching, filters, permissionsglobal $wpdb;$posts = $wpdb->get_results( "SELECT * FROM wp_posts WHERE post_type = 'product' AND post_status = 'publish'");// ❌ curl instead of wp_remote_get — ignores proxy settings, SSL config, hooks$ch = curl_init( 'https://api.example.com/data' );curl_setopt( $ch, CURLOPT_RETURNTRANSFER, true );$result = curl_exec( $ch );curl_close( $ch );// ❌ file_put_contents — wrong file owner on shared hosts, no FTP/SSH supportfile_put_contents( WP_CONTENT_DIR . '/exports/data.csv', $csv_data );// ❌ file_get_contents for URLs — no timeout, no SSL verification, no proxy$html = file_get_contents( 'https://example.com/feed.xml' );// ❌ mail() — skips wp_mail hooks, doesn't use configured SMTPmail( $to, $subject, $body );// ❌ json_encode for AJAX responses — missing headers, no hooksecho json_encode( [ 'success' => true ] );exit;
Custom tables not managed by WordPress (e.g., plugin-specific log tables)
Complex queries that WP_Query cannot express (multi-table JOINs)
Performance-critical batch operations (always use $wpdb->prepare())
Detection hints:
# Find raw PHP functions that have WP API equivalentsgrep -rn "curl_init\|file_put_contents\|file_get_contents.*http\|\bmail\s*(" wp-content/plugins/ --include="*.php"# Find direct header redirects instead of wp_redirectgrep -rn "header.*Location" wp-content/plugins/ --include="*.php"