Varnish with wordpress breaks the wordpress visual editor?

Hi I have a very weird issue with WordPress 3.5 Varnish 3.02 and Ubuntu where the visual editor has disappeared. The buttons to switch between the html/visual has disappeared and only the html editor is showing. The site is caching fine, no javascript error and no error in apache log. Varnish is listening on 80 and Apache on 8080. Everything else work fine except the editor.
When I bypass varnish the editor switch buttons appear and work fine. Here is what I have done so far without success:
– All plugins disabled
– Switched to Default theme
– Checked firebug for any jquery error (NONE)
– Bypassed Varnish (Everything works fine)
– Purged Varnish cache (No luck)
– Re-uploaded all default wordpress files
– Switched to an earlier version of WordPress (3.5)
What do you think might be the problem? I have been scratching my head for a week now on this issue.

VCL FILE

Read More
 backend default {
    .host = "x.x.x.x";
    .port = "8080";
 }


 sub vcl_recv {

  if (req.http.host ~ "mydomain.com") {
    set req.http.x-Redir-Url = "http://www.anotherdomain.com/specific_folder/";
    error 750 req.http.x-Redir-Url;
  }

 }

include "devicedetect.vcl";

# Called after a document has been successfully retrieved from the backend.
sub vcl_recv {
    call devicedetect;


    # Allow the back-end to serve up stale content if it is responding slowly.
    set req.grace = 2m;

    # Always cache the following file types for all users.
    if ( req.url ~ "(?i).(png|gif|jpeg|jpg|ico|swf|css|js|html|htm)(?[a-z0-9]+)?$" ) {
            unset req.http.cookie;
    }

    # Don't serve cached pages to logged in users
    if ( req.http.cookie ~ "wordpress_logged_in" || req.url ~ "vaultpress=true" ) {
            return( pass );
    }

    # Drop any cookies sent to WordPress.
    if ( ! ( req.url ~ "wp-(login|admin)" ) ) {
            unset req.http.cookie;
    }

    # Handle compression correctly. Different browsers send different
    # "Accept-Encoding" headers, even though they mostly all support the same
    # compression mechanisms. By consolidating these compression headers into
    # a consistent format, we can reduce the size of the cache and get more hits.
    # @see: http://varnish.projects.linpro.no/wiki/FAQ/Compression
    if ( req.http.Accept-Encoding ) {

            if ( req.http.Accept-Encoding ~ "gzip" ) {
                    # If the browser supports it, we'll use gzip.
                    set req.http.Accept-Encoding = "gzip";
            }

            else if ( req.http.Accept-Encoding ~ "deflate" ) {
                    # Next, try deflate if it is supported.
                    sset req.http.Accept-Encoding = "deflate";
            }
            else {
                    # Unknown algorithm. Remove it and send unencoded.
                    unset req.http.Accept-Encoding;
            }

    }

}

# MOBILE AND UA DETECTION - override the header before it is sent to the backend
sub vcl_miss { if (req.http.X-UA-Device) { set bereq.http.User-Agent = req.http.X-UA-Device; } }
sub vcl_pass { if (req.http.X-UA-Device) { set bereq.http.User-Agent = req.http.X-UA-Device; } }


sub vcl_fetch {
    #SET UA BEFORE SENDING TO BACKEND
    if (req.http.X-UA-Device) {
            if (!beresp.http.Vary) { # no Vary at all
                    set beresp.http.Vary = "X-UA-Device";
            } elseif (beresp.http.Vary !~ "X-UA-Device") { # add to existing Vary
                    set beresp.http.Vary = beresp.http.Vary + ", X-UA-Device";
            }
    }
    set beresp.http.X-UA-Device = req.http.X-UA-Device;



    #Fix Login under wordpress
    if (beresp.http.set-cookie ~ "sessionid" || beresp.http.set-cookie ~ "csrftoken") {
    #       return (pass);
    } else {
            return (deliver);
    }

    set beresp.ttl = 20m;

    # Allow items to be stale if needed.
    set beresp.grace = 2m;

    # Drop any cookies WordPress tries to send back to the client.
    if ( ! req.url ~ "wp-(login|admin)" && ! req.http.cookie ~ "wordpress_logged_in" ) {
            unset beresp.http.set-cookie;
    }

}

sub vcl_error {
 #REDIRECTION
    if (obj.status == 750) {
            set obj.http.Location = obj.response;
            set obj.status = 301;
            return (deliver);
    }

set obj.http.Content-Type = "text/html; charset=utf-8";
set obj.http.Retry-After = "5";
synthetic {"
    <?xml version="1.0" encoding="utf-8"?>
    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
    <html>
    <head>
    <title>OOPS UNE ERREUR S'EST PRODUITE</title>
    <style src="css/style.css"></style>
    </head>
    <body>
    <h1>Oh! Oh! Nos excuses. Une erreure s'est produite. On s'en occupe.</h1>
    </body>
    </html>
"};
    return (deliver);
}

sub vcl_deliver {
  if ((req.http.X-UA-Device) && (resp.http.Vary)) {
    set resp.http.Vary = regsub(resp.http.Vary, "X-UA-Device", "User-Agent");
  }
}


**************THIS IS ANOTHER FILE(devicedetect.vcl)**********************

INCLUDED DEVICE DETECTION:

#
# detectdevice.vcl - regex based device detection for Varnish
# http://github.com/varnish/varnish-devicedetect/
#
# Author: Lasse Karstensen <lasse@varnish-software.com>

sub devicedetect {
    unset req.http.X-UA-Device;
    set req.http.X-UA-Device = "pc";

    # Handle that a cookie may override the detection alltogether.
    if (req.http.Cookie ~ "(?i)X-UA-Device-force") {
            /* ;?? means zero or one ;, non-greedy to match the first. */
            set req.http.X-UA-Device = regsub(req.http.Cookie, "(?i).*X-UA-Device-force=([^;]+);??.*", "1");
            /* Clean up our mess in the cookie header */
            set req.http.Cookie = regsuball(req.http.Cookie, "(^|; ) *X-UA-Device-force=[^;]+;? *", "1");
            /* If the cookie header is now empty, or just whitespace, unset it. */
            if (req.http.Cookie ~ "^ *$") { unset req.http.Cookie; }
    } else {
            if (req.http.User-Agent ~ "(?i)(ads|google|bing|msn|yandex|baidu|ro|career|)bot" ||
                req.http.User-Agent ~ "(?i)(baidu|jike|symantec)spider" ||
                req.http.User-Agent ~ "(?i)scanner" ||
                req.http.User-Agent ~ "(?i)(web)crawler") {
                    set req.http.X-UA-Device = "bot"; }
            elsif (req.http.User-Agent ~ "(?i)ipad")        { set req.http.X-UA-Device = "tablet-ipad"; }
            elsif (req.http.User-Agent ~ "(?i)ip(hone|od)") { set req.http.X-UA-Device = "mobile-iphone"; }
            /* how do we differ between an android phone and an android tablet?
               http://stackoverflow.com/questions/5341637/how-do-detect-android-tablets-in-general-useragent */
            elsif (req.http.User-Agent ~ "(?i)android.*(mobile|mini)") { set req.http.X-UA-Device = "mobile-android"; }
            // android 3/honeycomb was just about tablet-only, and any phones will probably handle a bigger page layout.
            elsif (req.http.User-Agent ~ "(?i)android 3")              { set req.http.X-UA-Device = "tablet-android"; }
            // May very well give false positives towards android tablets. Suggestions welcome.
            elsif (req.http.User-Agent ~ "(?i)android")         { set req.http.X-UA-Device = "tablet-android"; }
            elsif (req.http.User-Agent ~ "Mobile.+Firefox")     { set req.http.X-UA-Device = "mobile-firefoxos"; }
            elsif (req.http.User-Agent ~ "^HTC" ||
                req.http.User-Agent ~ "Fennec" ||
                req.http.User-Agent ~ "IEMobile" ||
                req.http.User-Agent ~ "BlackBerry" ||
                req.http.User-Agent ~ "SymbianOS.*AppleWebKit" ||
                req.http.User-Agent ~ "Opera Mobi") {
                    set req.http.X-UA-Device = "mobile-smartphone";
            }
            elsif (req.http.User-Agent ~ "(?i)symbian" ||
                req.http.User-Agent ~ "(?i)^sonyericsson" ||
                req.http.User-Agent ~ "(?i)^nokia" ||
                req.http.User-Agent ~ "(?i)^samsung" ||
                req.http.User-Agent ~ "(?i)^lg" ||
                req.http.User-Agent ~ "(?i)bada" ||
                req.http.User-Agent ~ "(?i)blazer" ||
                req.http.User-Agent ~ "(?i)cellphone" ||
                req.http.User-Agent ~ "(?i)iemobile" ||
                req.http.User-Agent ~ "(?i)midp-2.0" ||
                req.http.User-Agent ~ "(?i)u990" ||
                req.http.User-Agent ~ "(?i)netfront" ||
                req.http.User-Agent ~ "(?i)opera mini" ||
                req.http.User-Agent ~ "(?i)palm" ||
                req.http.User-Agent ~ "(?i)nintendo wii" ||
                req.http.User-Agent ~ "(?i)playstation portable" ||
                req.http.User-Agent ~ "(?i)portalmmm" ||
                req.http.User-Agent ~ "(?i)proxinet" ||
                req.http.User-Agent ~ "(?i)sonyericsson" ||
                req.http.User-Agent ~ "(?i)symbian" ||
                req.http.User-Agent ~ "(?i)windows ?ce" ||
                req.http.User-Agent ~ "(?i)winwap" ||
                req.http.User-Agent ~ "(?i)eudoraweb" ||
                req.http.User-Agent ~ "(?i)htc" ||
                req.http.User-Agent ~ "(?i)240x320" ||
                req.http.User-Agent ~ "(?i)avantgo") {
                    set req.http.X-UA-Device = "mobile-generic";
            }
    }

}

Related posts

Leave a Reply

2 comments

  1. I’ve stumbled upon this question while having the same issue. I tried doing what the asker suggested in the follow-up “response” but I was out of luck.

    The problem that was described in the question arises from the fact that WordPress enables the TinyMCE (Visual) editor only when the user-agent matches a known one. For everything else, it will disable it by default. Combined with devicedetect.vcl, you can probably see where this is going…

    So, because we are sending “pc”, “mobile-platform” etc. to the backend (WordPress), it will never actually know the browser you are using.

    In my VCL I disable caching for /wp-admin completely with the following code:

    if (req.url ~ "/wp-(login|admin)") {
        return (pass);
    }
    

    When I implemented devicedetect.vcl I was calling the routine at the top of my sub vcl_recv, thus the user-agent was already reaching my backend in a modified state.

    The solution is to return (pass) on /wp-(login|admin) BEFORE you call devicedetect, like this:

    if (req.url ~ "/wp-(login|admin)") {
        return (pass);
    }
    call devicedetect;
    
  2. Yes it was happening whether logged in or not.

    The issue was with the call to devicedetect in the vcl_recv. I created a new vcl_recv after the first to handle the devicedetect routine. This somehow fixed the problem.

    Thanks