• Summary:
    ======================

    Page cache (page_enhanced), nginx rules that created by w3tc plugin have a bug that causes nginx to not serve cached file and force wordpress to handle request. I have tested it on w3tc 0.9.4.

    Reproduction steps:
    ======================

    1) Activate w3tc page cache with page_enhanced mode.

    2) copy/paste or include the nginx config file created by w3tc

    3) Add “return 504;” (504 or else) into this if block to proof that nginx in not directly using cached response.

    if (-f "$document_root/wp-content/cache/page_enhanced/$http_host/$request_uri/_index$w3tc_rewrite.html$w3tc_enc") {
    	return 504;
        set $w3tc_ext .html;
    }

    4) restart nginx (or test config files with -t and reload nginx)

    5) log out wordpress

    6) Clear you browser’s cache.

    7) request a page https://your-site.com/

    8) Refrest (F5) to request the same page again https://your-site.com/

    9) You will not see a 504 gateway timeout error.

    This is the proof that the above if {} block is never executed. nginx does not directly returned the cached copy of page.

    Yes, the cached copy of file is returned but;

    Instead of just nginx, wordpress handled the request and gived out extra effort, w3tc plugin read out the cached copy of file.

    (WordPress always achieves to handle the request because of “try_files” directive at your “/” or “php” location block)

    Cause:
    ======================

    nginx rules that created by w3tc plugin have a bug.

    Please look the created rules:

    set $w3tc_rewrite 1;
    ...
    ...
    if (-f "$document_root/wp-content/cache/page_enhanced/$http_host/$request_uri/_index$w3tc_rewrite.html$w3tc_enc") {
        set $w3tc_ext .html;
    }

    As I understand w3tc plugin will never create a file like “_index1.html”. So the above if {} block will always fail.

    Solution/FIX:
    ======================

    Change:
    $w3tc_rewrite 1;
    as:
    set $w3tc_rewrite "";

    Change:
    if ($w3tc_rewrite = 1) {
    as:
    if ($w3tc_rewrite != 0) {

    At the end, nginx rules that created by w3tc plugin sholud be as follows:

    # BEGIN W3TC Page Cache cache
    location ~ /wp-content/cache/page_enhanced.*html$ {
        add_header Vary "Accept-Encoding, Cookie";
        add_header Pragma "no-cache";
        add_header Cache-Control "max-age=0, private, no-store, no-cache, must-revalidate";
    }
    location ~ /wp-content/cache/page_enhanced.*gzip$ {
        gzip off;
        types {}
        default_type text/html;
        add_header Vary "Accept-Encoding, Cookie";
        add_header Pragma "no-cache";
        add_header Cache-Control "max-age=0, private, no-store, no-cache, must-revalidate";
        add_header Content-Encoding gzip;
    }
    # END W3TC Page Cache cache
    # BEGIN W3TC Page Cache core
    #set $w3tc_rewrite 1;
    set $w3tc_rewrite "";
    if ($request_method = POST) {
        set $w3tc_rewrite 0;
    }
    if ($query_string != "") {
        set $w3tc_rewrite 0;
    }
    if ($http_cookie ~* "(comment_author|wp\-postpass|w3tc_logged_out|wordpress_logged_in|wptouch_switch_toggle)") {
        set $w3tc_rewrite 0;
    }
    if ($http_user_agent ~* "(W3\ Total\ Cache/0\.9\.4)") {
        set $w3tc_rewrite 0;
    }
    if ($http_cookie ~* "(w3tc_preview)") {
        set $w3tc_rewrite _preview;
    }
    set $w3tc_enc "";
    if ($http_accept_encoding ~ gzip) {
        set $w3tc_enc _gzip;
    }
    set $w3tc_ext "";
    if (-f "$document_root/wp-content/cache/page_enhanced/$http_host/$request_uri/_index$w3tc_rewrite.html$w3tc_enc") {
        set $w3tc_ext .html;
    }
    if (-f "$document_root/wp-content/cache/page_enhanced/$http_host/$request_uri/_index$w3tc_rewrite.xml$w3tc_enc") {
        set $w3tc_ext .xml;
    }
    if ($w3tc_ext = "") {
      set $w3tc_rewrite 0;
    }
    #if ($w3tc_rewrite = 1) {
    if ($w3tc_rewrite != 0) {
        rewrite .* "/wp-content/cache/page_enhanced/$http_host/$request_uri/_index$w3tc_rewrite$w3tc_ext$w3tc_enc" last;
    }
    # END W3TC Page Cache core

    Thanks

    https://www.ads-software.com/plugins/w3-total-cache/

Viewing 5 replies - 1 through 5 (of 5 total)
  • Thread Starter naklov

    (@naklov)

    Sorry for the “nocache” headers, I forgot there.

    The fix is still valid.

    The error is deeper. Please fix following lines in wp-content/plugins/w3-total-cache/lib/W3/PgCacheAdminEnvironment.php from beginning from line 960 (tested with version 0.9.4.1):

    /**
    * Check for preview cookie
    */
    $rules .= "if (\$http_cookie ~* \"(w3tc_preview)\") {\n";
    $rules .= " set \$w3tc_rewrite _preview;\n";
    $rules .= "}\n";
    $env_w3tc_preview = "\$w3tc_rewrite";

    It should be:

    /**
    * Check for preview cookie
    */
    $rules .= "if (\$http_cookie ~* \"(w3tc_preview)\") {\n";
    $rules .= " set \$w3tc_preview _preview;\n";
    $rules .= "}\n";
    $env_w3tc_preview = "\$w3tc_preview";

    They did a mistake by using w3tc_rewrite and not w3tc_preview. w3tc_rewrite is used in the generated nginx.conf in a different context, so it should be w3tc_preview. After the correction the generated nginx.conf works perfectly!

    I noticed the same problem. The pages are definitely not being served from the cache. Any update from the plugin author?

    I sent the author a message with the fix included. If you change the lines in PgCacheAdminEnvironment.php it should work. For me it is definitively an programming failure at the time the nginx.conf is generated. I tested my fix with version W3 Total Cache 0.9.4.1. Changing the nginx.conf directly (as described at the top of this post or in other posts will only fix it until you change the settings of the plugin, since the file is completely generated for every new setting). Don’t forget to include the generated nginx.conf in you nginx config.

    Same problem here, will you fix it?

Viewing 5 replies - 1 through 5 (of 5 total)
  • The topic ‘BUG FIX: nginx rules – page_enhanced cache’ is closed to new replies.