Performance is the #1 concern for enterprise clients. These questions test knowledge of caching layers, database optimization, and profiling.
1. Explain the different layers of caching in a WordPress stack.
Answer:
- Browser Cache: Static assets (CSS, JS, Images) stored in the user's browser.
- Page Cache (Varnish/Nginx/Plugin): Stores the fully rendered HTML of a page. The fastest way to serve content.
- Object Cache (Redis/Memcached): Stores database query results (e.g., `get_option`, `get_post_meta`) in memory to avoid hitting the primary database (MySQL/Postgres).
- Opcode Cache (OPcache): Stores compiled PHP bytecode in memory so PHP doesn't have to re-compile scripts on every request.
2. What is the N+1 Query Problem and how do you fix it in WordPress?
Answer: It happens when code executes one query to fetch a list of items, and then an additional query for each item in that list.
Example: Looping through 100 posts and getting the author name for each.
Fix:
- Use functions that cache data automatically (WordPress core does this for many things).
- Use `update_post_caches()` or `WP_Query` with `cache_results => true`.
- Prefetch data. For example, if you need meta for 100 posts, fetch all meta in one query using `update_meta_cache()`.
3. How do you optimize a slow `WP_Query`?
Answer:
- Limit fields: Use `'fields' => 'ids'` if you only need IDs.
- No Found Rows: Use `'no_found_rows' => true` to skip counting total results (pagination) if not needed.
- Avoid Meta Queries: Complex `meta_query` (especially with `LIKE` or multiple joins) kills performance. Use custom tables or search indexes (Elasticsearch) instead.
- Cache Results: Ensure Object Cache is active.
4. What are Transients and when should you use them?
Answer: Transients are a standardized way to store cached data in the database (or Object Cache) with an expiration time.
Use Case: Storing the result of an expensive external API call (e.g., Instagram feed) or a complex calculation.
$data = get_transient('my_api_data');
if (false === $data) {
$data = remote_api_call();
set_transient('my_api_data', $data, 12 * HOUR_IN_SECONDS);
}
5. How would you debug a slow loading page?
Answer:
- Query Monitor: Use this plugin to see slow queries, PHP errors, and hook execution times.
- New Relic: For production profiling to pinpoint specific functions or external calls causing delays.
- WP-CLI: `wp profile` commands.
- Check Logs: PHP error logs and server access logs.
6. What is the difference between `wp_cache_set` and `set_transient`?
Answer:
- `wp_cache_set` (Object Cache): Stores data in memory (RAM) for the duration of the request. If a persistent object cache (Redis/Memcached) is installed, it persists across requests. It is non-blocking and very fast.
- `set_transient` (Database/Object Cache): Stores data in the `wp_options` table by default (with an expiration). If a persistent object cache is present, it acts like `wp_cache_set`.
Key Difference: Without an external object cache, `wp_cache_set` data is lost when the page finishes loading. Transients persist in the DB even without Redis.
7. How do you optimize the `wp_options` table?
Answer: The `wp_options` table can become bloated, slowing down every page load because "autoloaded" options are fetched on every request.
Optimization Strategies:
- Clean up Autoloaded Data: Identify large options with `autoload='yes'` that aren't needed on every page and set them to `'no'`.
- Remove Stale Transients: Old transients can clutter the table. Use a DB cleaner or WP-CLI `wp transient delete --expired`.
- Index: Ensure the `autoload` column is indexed (it is by default in modern WP).
8. Explain "Lazy Loading" in the context of WordPress images.
Answer: Lazy loading defers the loading of off-screen images until the user scrolls near them. This improves the initial "Largest Contentful Paint" (LCP) score.
Implementation:
- Native: WordPress (since 5.5) adds `loading="lazy"` attribute to `img` tags automatically.
- Optimization: You should disable lazy loading for the "hero" image (above the fold) to ensure it loads immediately, improving LCP.
// Disable lazy loading for the first image
add_filter( 'wp_get_attachment_image_attributes', function( $attr ) {
if ( is_hero_image() ) {
$attr['loading'] = 'eager';
}
return $attr;
});