For how I figured this out, skip to after the instructions:
I have not seen an answer to the various versions of this question, ie: when using jetpack, wptouch, etc, so I hope this will help those who are facing this issue.
I am running a site using --wp --wpfc, It has wptouchpro. Previous attempts have cause either mobile or desktop versions to be shown to both device types after the first one accesses the page.
This is a refined version as stated on: https://www.alpine.link/2015/04/25/fastcgi_cache-purging/
WARNING: This method edits core easy engine files which WILL be REPLACED on an update !!
How to - Quick & Easy:
nginx.conf - Add:
map $http_user_agent $mobile_request
{
default fullversion;
"~*ipad" fullversion;
"~*android.*mobile" mobileversion;
"~*iphone" mobileversion;
"~*ipod.*mobile" mobileversion;
"~*BlackBerry*Mobile Safari" mobileversion;
"~*BB*Mobile Safari" mobileversion;
"~*Opera.*Mini/7" mobileversion;
"~*IEMobile/10.*Touch" mobileversion;
"~*IEMobile/11.*Touch" mobileversion;
"~*IEMobile/7.0" mobileversion;
"~*IEMobile/9.0" mobileversion;
"~*Firefox.*Mobile" mobileversion;
"~*webOS" mobileversion;
}
/etc/nginx/conf.d/fastcgi.conf
# FastCGI cache settings
fastcgi_cache_path /var/run/nginx-cache levels=1:2 keys_zone=WORDPRESS:50m inactive=60m;
fastcgi_cache_key "$scheme$request_method$host$request_uri$mobile_request";
fastcgi_cache_use_stale error timeout invalid_header updating http_500 http_503;
fastcgi_cache_valid 200 301 302 404 1h;
fastcgi_buffers 16 16k;
fastcgi_buffer_size 32k;
fastcgi_param SERVER_NAME $http_host;
fastcgi_ignore_headers Cache-Control Expires Set-Cookie;
fastcgi_keep_conn on;
/etc/nginx/common/wpfc.conf
# WPFC NGINX CONFIGURATION
# DO NOT MODIFY, ALL CHANGES LOST AFTER UPDATE EasyEngine (ee)
set $skip_cache 0;
set $var_desktop "fullversion";
set $var_mobile "mobileversion";
# POST requests and URL with a query string should always go to php
if ($request_method = POST) {
set $skip_cache 1;
}
if ($query_string != "") {
set $skip_cache 1;
}
# Don't cache URL containing the following segments
if ($request_uri ~* "(/wp-admin/|/xmlrpc.php|wp-.*.php|index.php|/feed/|sitemap(_index)?.xml|[a-z0-9_-]+-sitemap([0-9]+)?.xml)") {
set $skip_cache 1;
}
# Don't use the cache for logged in users or recent commenter
if ($http_cookie ~* "comment_author|wordpress_[a-f0-9]+|wp-postpass|wordpress_no_cache|wordpress_logged_in") {
set $skip_cache 1;
}
# Use cached or actual file if they exists, Otherwise pass request to WordPress
location / {
try_files $uri $uri/ /index.php?$args;
}
location ~ ^/wp-content/cache/minify/(.+\.(css|js))$ {
try_files $uri /wp-content/plugins/w3-total-cache/pub/minify.php?file=$1;
}
location ~ \.php$ {
try_files $uri =404;
include fastcgi_params;
fastcgi_pass php;
fastcgi_cache_bypass $skip_cache;
fastcgi_no_cache $skip_cache;
fastcgi_cache WORDPRESS;
}
if ($http_cookie ~ 'wptouch-pro-view=desktop') {
set $mobile_request fullversion;
}
location ~ /purge(/.*) {
access_log off ; log_not_found off;
fastcgi_cache_purge WORDPRESS $scheme$request_method$host$1$var_desktop;
}
location ~ /mpurge(/.*) {
access_log off ; log_not_found off;
fastcgi_cache_purge WORDPRESS $scheme$request_method$host$1$var_mobile;
}
wp-content/plugins/nginx-helper/purger.php
Look for function purgeUrl - default - replace with:
$_url_purge_base = $parse[ 'scheme' ] . '://' . $parse[ 'host' ] . '/purge' . $parse[ 'path' ];
$_url_purge = $_url_purge_base;
$_url_purge_base_m = $parse[ 'scheme' ] . '://' . $parse[ 'host' ] . '/mpurge' . $parse[ 'path' ];
$_url_purge_m = $_url_purge_base_m;
if ( isset( $parse[ 'query' ] ) && $parse[ 'query' ] != '' ) {
$_url_purge .= '?' . $parse[ 'query' ];
$_url_purge_m .= '?' . $parse[ 'query' ];
}
$this->_do_remote_get( $_url_purge );
$this->_do_remote_get_m( $_url_purge_m );
if ( $feed ) {
$feed_url = rtrim( $_url_purge_base, '/' ) . '/feed/';
$feed_url_m = rtrim( $_url_purge_base_m, '/' ) . '/feed/';
$this->_do_remote_get( $feed_url );
$this->_do_remote_get_m( $feed_url_m );
$this->_do_remote_get( $feed_url . 'atom/' );
$this->_do_remote_get_m( $feed_url_m . 'atom/' );
$this->_do_remote_get( $feed_url . 'rdf/' );
$this->_do_remote_get_m( $feed_url_m . 'rdf/' );
}
Add new function after function _do_Remote_get:
private function _do_remote_get_m( $url ) {
$user_args = array(
'user-agent' => 'Mozilla/5.0 (iPhone; CPU iPhone OS 9_1 like Mac OS X) AppleWebKit/601.1.46 (KHTML, like Gecko) Version/9.0 Mobile/13B143 Safari/601.1'
);
$response = wp_remote_get( $url ,$user_args);
if ( is_wp_error( $response ) ) {
$_errors_str = implode( " - ", $response->get_error_messages() );
$this->log( "Error while purging URL. " . $_errors_str, "ERROR" );
} else {
if ( $response[ 'response' ][ 'code' ] ) {
switch ( $response[ 'response' ][ 'code' ] ) {
case 200:
$this->log( "- - " . $url . " *** PURGED ***" );
break;
case 404:
$this->log( "- - " . $url . " is currently not cached" );
break;
default:
$this->log( "- - " . $url . " not found (" . $response[ 'response' ][ 'code' ] . ")", "WARNING" );
}
}
}
}
Diagnostics:
Following those instructions, I got the server to create 2x versions of the page cached correctly. Using the key constructor ($scheme$request_method$host$request_uri$mobile_request) I used an online md5 generator to find the cache files and everything was working 100%.
Mobile requests were created using the inspector in chrome, set to an iPhone 6s.
I then modified the nginx helper plugin to do 2x calls, one to /purge, and the other to /mpurge. The main issue I faced was that the desktop version was getting purged, but the mobile version was not.
After several hours of diagnostics I perchance accessed the /mpurge url from the inspector in Mobile mode, and it cleared the mobile version !!
My hypothesis is that somehow, even though I can access the /mpurge from the server or desktop page request, you will always get 404 not found if the user agent is not one of those it detects as a mobile agent.
To fix this issue, I created a second function _do_remote_get_m which adds a user-agent arg to the wp_remote_get option. And then EVERYTHING started working correctly.
I am going to duplicate this to my production server, and fix any issues. Thought I would get this out there so long.
Enjoy !!