Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

Less and faster – Cache tips for WordPress developers


Published on

Otto Kekäläinen, the code-loving CEO of Seravo held a webinar on May 12, 2020, that focused on the cache: what should a WordPress developer know and which are the best practices to follow?

Published in: Internet
  • Be the first to comment

  • Be the first to like this

Less and faster – Cache tips for WordPress developers

  1. 1. Less and faster Caching tips for WordPress developers
  2. 2. Who, where, and why?
  3. 3. Premium hosting and upkeep for WordPress HTTP/2 TESTED UPDATES 24/7 UPKEEP
  4. 4. Top-notch performance A comparison published by a Google employee at confirms that Seravo’s customer sites load faster than competing services’. The study used time-to-first-byte (TTFB) measurement data from real users as collected from the Chrome browser UX data. Fast/Average/Slow TTFB by WordPress Host
  5. 5. “There are only two hard things in Computer Science: cache invalidation and naming things.” – Phil Karlton
  6. 6. Caches are everywhere ● Inside the CPU (levels L1-L4). ○ No need to retrieve data from RAM over and over again. ● In operating system (Linux) to protect the hard drives. ○ Prevents different programs from continuously reading the same file from the hard drive. ● Some programs have built-in caches: ○ PHP ■ Saves files so that there is no need to download them from the hard drive every second. ■ Saves the interpreted PHP code so that it does not have to be constantly recompiled. ○ Database ■ Uses plenty of cache (RAM) so that the hard drive does not need to be read as often. ○ WordPress ■ Stores transients in the database so that the following queries do not have to be as extensive. ...and these are just couple of examples. The list is long.
  7. 7. Caches are everywhere, because...? ● Speed! ○ Can you say instantly how much is 5 times 5? Yes, because the result is already in your memory. ○ How about 55 times 555? Hmm… Probably have to count that one. ● Not everything can be stored in the memory, so it is a good idea to save only things you are likely need several times again later on.
  8. 8. The numbers every coder should know ● Retrieval times for different types of memories: ○ L1 cache: 1 nanosecond ○ L2 cache: 3 ns ○ L3 cache: 10 ns ○ RAM: 25 ns ○ PCIe NVMe hard drive: 2000 ns – most Seravo customers ○ SSD hard drive: 100 000 ns – few Seravo customers ○ HDD hard drive: 10 000 000 ns – none of Seravo’s customers ○ Tampere-Berlin ping: 30 000 000 ns ○ HTML-page from Nginx 2 000 000 ns ○ HTML-page from PHP/WP 50 000 000 – 1 000 000 000 ns
  9. 9. Should the cache contain everything? ● Not everything can be stored in the memory, so you should only store things that will most likely be needed twice or more. ● If something is not needed, clear the cache: ○ Clearing by command, so called “cache purge”. ○ A built-in mechanism, e.g. a counter to tell how many times the data has been retrieved in the past hour. ● The cache can be cleared at any time, and some systems do so on a regular basis. ● In addition, the cache can expire.
  10. 10. Difficult: Cache invalidation ● In what time will the cache expire? ○ 5 seconds? ○ 60 seconds? ○ 15 minutes? ○ 7 days? ● It depends. That is why it is so difficult.
  11. 11. Cache concepts Retrieval time – has to be faster from cache than the source in order to get savings. Invalidation – the criteria for deleting data from the cache. Expiry – the time in which the data expires and is removed from the cache. Bypass – intentionally bypasses the cache. Miss – if the cache is empty, retrieves the latest data. Hit rate – hit/miss-ratio, how often the data was found in the cache (ideally 99,99 %).
  12. 12. Caches in WordPress sites
  13. 13. For a WP developer to consider ● Browser HTTP cache ○ Always the fastest! ● Server HTTP cache ○ Nginx, Varnish, Cloudflare, Fastly etc. ● WordPress transients ○ get_transient(key); ● WordPress object cache ○ wp_cache_get(key); ● File system cache ● MariaDB database cache See also:
  14. 14. No, another plugin is not the way to go. It might be a band-aid, at best.
  15. 15. Browser HTTP cache ● Objective: to avoid unnecessary network traffic. ● The browser stores pages and files purely based on what the HTTP headers say. ● Make sure your site sends sensible HTTP headers and content expiration dates. ● WordPress does not do this as a standard.
  16. 16. An example: WP 5.3.2 CSS file $ curl -IL HTTP/2 200 server: nginx date: Wed, 29 Apr 2020 05:33:47 GMT content-type: text/css last-modified: Tue, 28 Apr 2020 11:42:09 GMT etag: "5ea81691-1d52e" expires: Thu, 07 May 2020 05:33:45 GMT cache-control: max-age=691200 x-proxy-cache: HIT P: A: N: H:0 O: S: x-powered-by: Seravo x-seravo-request-id: dd1d5d1e649b5f675269a54e86dabacb The server tells the browser that the content is valid for seven days. The length of the time does not matter. However, the content in the address style.min.css?ver=5.3.2 stays the same so it must be updated with a new version number if the content is updated. Otherwise the page will be “broken” for seven days for old visitors.
  17. 17. An example: theme’s CSS file wp_enqueue_style( 'seravo', get_stylesheet_directory_uri() . '/dist/layout.min.css', false, wp_get_theme()->get('Version') ); => If you download style files or scripts without version numbers, the browser will always have the same layout.min.css. However, if you add the version number, the download happens with an address layout.min.css?ver=1.2.3 which ensures that whenever there is a new version of the theme, the browser will also download a new version of the style file.
  18. 18. An example: CSS file wp_enqueue_style( 'seravo', get_stylesheet_directory_uri() . '/dist/layout.min.css', false, seravo_get_git_commit_id() ); => function seravo_get_git_commit_id() { // Don't use shell_exec('git rev-parse --short HEAD') or similar since it // would spawn a shell session on every WordPress load of every page. // Instead read directly from .git/logs/HEAD to as efficient as possible. $git_log_file = '/data/wordpress/.git/logs/HEAD'; if ( is_readable($git_log_file) ) { $lines = file($git_log_file); $last_line = array_pop($lines); $fields = explode(' ', $last_line); return substr($fields[1], 0, 8); } else { return wp_get_theme()->get('Version'); } }
  19. 19. Content expiration date header.php: $seconds_to_cache = 3600; // 1 hour $ts = gmdate("D, d M Y H:i:s", time() + $seconds_to_cache) . " GMT"; header("Expires: $ts"); header("Cache-Control: max-age=$seconds_to_cache"); => expires: Wed, 29 Apr 2020 06:55:49 GMT cache-control: max-age=3600 In dynamic files the validity period comes from PHP. WordPress itself does not set a default expiration date. If desired, the theme can set it using HTTP headers if the page is rarely updated or the refresh delay is irrelevant. The validity period for static files (e.g. style.css or script.js) comes from the HTTP server settings. At Seravo static files have seven day expiration and cache control by default.
  20. 20. Blocking content expiration date nocache_headers(); => expires: Wed, 11 Jan 1984 05:00:00 GMT cache-control: no-cache, must-revalidate, max-age=0 WordPress (or a theme or a plugin) sometimes blocks itself the content expiration date with a nocache_headers() -function.
  21. 21. Server HTTP cache ● Objective: to avoid unnecessary PHP execution and to provide an HTML file directly from the memory. ● The server cache (as well as the browser!) stores pages and files purely based on what the HTTP headers say. ● Once again, make sure your site sends sensible HTTP headers and content expiration dates.
  22. 22. Tool: wp-speed-test $ wp-speed-test Testing speed URL URL TOTAL NAMELOOKUP CONNECT APPCONNECT PRETRANSFER STARTTRANSFER = AVG 0.161 0.004 0.005 0.011 0.011 0.159 0.161 0.124 0.000 0.000 0.000 0.000 0.122 0.142 0.113 0.000 0.000 0.000 0.000 0.111 0.132 0.216 0.000 0.000 0.000 0.000 0.215 0.153 $ wp-speed-test --cache Testing speed URL Warning: invoked with --cache and thus measuring cached results. This does not measure actual PHP speed. URL TOTAL NAMELOOKUP CONNECT APPCONNECT PRETRANSFER STARTTRANSFER = AVG 0.015 0.004 0.004 0.012 0.012 0.013 0.015 0.009 0.000 0.000 0.000 0.000 0.007 0.009 0.002 0.000 0.000 0.000 0.000 0.001 0.006 0.006 0.000 0.000 0.000 0.000 0.005 0.006 If --cache gives a better result, the HTTP-level server cache is working correctly. By default, the wp-speed-test always overrides the cache (it is not nginx- but wp-speed-test).
  23. 23. Tool: wp-check-http-cache $ wp-check-http-cache ---------------------------------------- Seravo HTTP cache checker ---------------------------------------- Testing Request 1: MISS Request 2: MISS Request 3: MISS ---------------------------------------- FAILED: HTTP cache does not work for ---------------------------------------- Please review these headers and try to find what emits them: expires: Wed, 11 Jan 1984 05:00:00 GMT cache-control: no-transform, no-cache, no-store, must-revalidate ---------------------------------------- You can also test this yourself by running: curl -IL The site probably has WP_DEBUG or nocache_headers() on through some other route because of the 1984.
  24. 24. Tool: wp-check-http-cache $ wp-check-http-cache ---------------------------------------- Seravo HTTP cache checker ---------------------------------------- Testing Request 1: HIT Request 2: HIT Request 3: HIT ---------------------------------------- SUCCESS: HTTP cache works for ---------------------------------------- You can also test this yourself by running: curl -IL The site is not sending HTTP headers that would prevent server-level caching.
  25. 25. Intentionally bypassing the cache Most sites want HTTP-level caching enabled. An exception is a page that has content customized for one user only, such as showing “Hello Otto!” to an identified user or a WooCommerce shopping cart. By default the shopping cart is displayed empty and caching is enabled, but as soon as the user puts something in the cart, customized content should be displayed to that particular visitor, and the event should not be cached. WooCommerce makes sure this happens by setting cookies woocommece_items_in_cart and woocommerce_cart_hash that automatically prevent the cache from working, as they indicate user-specific content.
  26. 26. Can the server cache slow down the page? Additional layers of caching can reduce the need to retrieve information directly from the source. The best cache is in the browser itself. An attractive option may be to cache a server that is close to the user. However, recycling traffic through the CDN can also increase the delay. For example, the direct connection is 90 ms but the use of WooCommerce via CDN is 60 + 60 ms = 120 ms => 30 % slower. Be sure to measure before and after! Read more: Open the shopping cart User in Berlin Server in Helsinki Server in Amsterdam HTTP/2-connection, connect+fetch 90 ms HTTP/2-connection, c+f 60 ms HTTP/2-connection, c+f 60 ms
  27. 27. Seravo’s feature: server caching ● A standard WordPress page is server-level cached for 10 minutes by default (see the action by looking at HIT/MISS lines in the HTTP response). ● The server-level cache can be cleared with the wp-purge-cache command. ● ...or skipped by loading the page with Ctrl+F5. ● If the page is broken (e.g. PHP syntax error), stale cache enters the game and displays the page from the cache while the coder adds the missing semicolon etc.
  28. 28. WordPress transients ● Objective: to avoid repeated heavy network and database queries within the same minute or an hour.
  29. 29. WordPress transients // Check for transient. If none, then execute WP_Query if ( false === ( $featured = get_transient( 'foo_featured_posts' ) ) ) { $featured = new WP_Query( array( 'category' => 'featured', 'posts_per_page' => 5 )); // Put the results in a transient. Expire after 12 hours. set_transient( 'foo_featured_posts', $featured, 12 * HOUR_IN_SECONDS ); } WordPress’ own built-in cache for storing data for later use (e.g. one minute or one hour). Stores in the database by default, but can also use for example only RAM if object-cache.php is used and e.g. Redis server is available (as is the case for all Seravo clients). Transient API in brief: get_transient(), set_transient() ja delete_transient() For more information: Always remember expiry! Otherwise WP may load data via wp_load_alloptions() with each site load!
  30. 30. WordPress object cache ● Objective: to avoid repetitive database queries during the same PHP page load.
  31. 31. WP object cache function prefix_get_post_count( $post_status = 'publish' ) { $cache_key = 'prefix_post_count_'. $post_status; $_posts = wp_cache_get( $cache_key ); if ( false === $_posts ) { $_posts = $wpdb->get_var( $wpdb->prepare( "SELECT COUNT(*) FROM $wpdb->posts WHERE post_type = 'post' AND post_status = %s", $post_status )); wp_cache_set( $cache_key, $_posts ); } return $_posts; } For example, stores database query results in PHP’s memory, so that queries made in different parts of WordPress code during the same PHP run do not have to be repeated many times. NOTE: I have never used wp_cache_*. The Transient API is what a site developer really needs! Example page
  32. 32. File system cache ● Objective: to avoid unnecessary hard drive operations in general for any program. ● Seravo’s got you covered!
  33. 33. Database cache ● Objective: to avoid unnecessary hard drive operations in the database in particular. ● Seravo’s got you covered!
  34. 34. Tideways Xdebug is a good tool for profiling PHP code in a local development environment. In a production environment Seravo recommends service.
  35. 35. Instructions for WordPress site developers
  36. 36. Always remember to measure before and after!
  37. 37. Thank you! @Seravo @ottokekalainen
  38. 38. See also Make Your Site Faster with Caching 300% faster WordPress load times with transients 5 common reasons why your WordPress site is slow Improving WordPress Performance with XDebug and PHP Profiling