Tag Archives: wordpress

Varnish A/B Testing

Cloudflare doesn’t cache any of our PHP files so don’t need to worry about that. Cloudflare connects to our nginx SSL reverse proxy.

nginx has a split_clients directive, so could potentially add header there:

Performing A/B Testing with NGINX and NGINX Plus

The SSL reverse proxy connects to a varnish server on the same system.

Varnish can also set the a/b testing header:
https://info.varnish-software.com/blog/live-ab-testing-varnish-and-vcs

Where ever the header is set, Varnish will need to Vary based on that header.

Varnish then connects to nginx, which then connects to the php-fpm server(s). At this point, there needs to be a different wordpress instance loaded, and there are a couple different ways.

The main idea I have now is to bind mount different plugin and theme directories on top of a base directory. The base directory contains the basic wordpress install, and the images, etc (basically everything not themes/plugins). One easy way to do this is with containers, but you should be able to do it outside containers as well.

No Containers Method:
– bind mount base directory to branch directory (ie /vhosts/base -> /vhosts/test-a)
– bind mount plugins and theme directories on top (ie /usr/src/test-a/plugins -> /vhosts/test-a/wordpress/wp-content/plugins)
– map header to root directories in nginx: (needs to be in http block)
https://serversforhackers.com/c/nginx-mapping-headers
#should use mapping so that there is always a default (don’t trust header)
map $http_ab_group $ati_ab_dir {
default “all-that-is-interesting”;
a “test-a”;
}
server {
server_name allthatsinteresting.com;
server_name www.allthatsinteresting.com;
root /vhosts/$ati_ab_dir;
}

Containers Method:
– switch nginx config to use containers (basically need to use a reverse proxy instead of fastcgi)
– which reverse proxy to use would be mapped in from the header
– containers would have the base dir, plugins dir, and themes dir mounted as volumes

Containers method would require more work, and the worker pool will be segmented among the php-fpm backends, so it’s more difficult to size the max workers per container. Like say the server has memory to handle 128 workers, if you have 3 separate worker pools, do you assume that all 3 pools will be maxed, or do you oversubscribe since chances are the load will be uneven? It’s simpler and safer to just have a single PHP backend. (not to mention the added complexity of Docker)

wordpress and HTTPS

– Cloudflare: add page rules for https://kitwestneat.com/wordpress/wp-admin* and https://kitwestneat.com/wordpress/wp-login* to have full SSL

– WordPress: add $_SERVER[‘HTTPS’] = ‘on’; to wp-config
– WordPress: change addresses in general settings
– Cloudflare: set site wide SSL to flexible
– Cloudflare: set Always use HTTPS on
– Monitis: enable SNI, make sure URL is not using :80

Converting EPS Redirects to Nginx Redirects

EPS exports as a CSV, with the fields redirect type, incoming URI, outgoing URL or post ID, number of hits so far. If the incoming URL has commas, it doesn’t properly escape them, so that needs to be checked by grepping for lines with more than 3 commas:
egrep ‘(.*,){4,}’ ~/Downloads/2016-08-24-redirects.csv

The redirects csv should also be checked for spaces, parens, and ? in the URIs, and the spaces should be converted to %20 before running the script, and parens to \(.

eps2nginx.sh:

CSV=/tmp/eps-redirects.csv
for uri_redir in $(cat $CSV | awk -F, '{ print $2"," $3 }'); do
uri=$(cut -d, -f1 <<< "$uri_redir") redir=$(cut -d, -f2 <<< "$uri_redir") case $redir in ''|*[!0-9]*) ;; *) redir=$(wp post list --post__in=$redir --field=url 2> /dev/null);;
esac

echo "rewrite ^/${uri}$ $redir permanent;"
done

Using wp tool to update wordpress no index

wp post meta update _yoast_wpseo_meta-robots-noindex 1

You can use url_to_postid to convert a URL to its post id in the wp shell, or by creating a wp command.

for url in $(cat /tmp/urls-to-noindex); do
id=$(wp url2id $url)
if [ "$id" == "0" ]; then
echo $url - no post found
else
wp post meta update $id _yoast_wpseo_meta-robots-noindex 1
fi;
done

Create scaffolding for a command with wp scaffold plugin.

command.php snippet:

$url2post_command = function($args) {
if (count($args) == 0) {
WP_CLI::fail("no url");
return;
}
$post_id = url_to_postid($args[0]);
echo "$post_id\n";
};
WP_CLI::add_command( 'url2post', $url2post_command );

*BONUS* how to get post publish date:
wp post get –field=post_date
(or post_modified)

WordPress xmlrpc with a different Host header in Python

If you are ever in a situation where you need to run an xmlrpc request against a specific WordPress server using the python xmlrpc library, it can be somewhat difficult. The Python xmlrpc library doesn’t give you an easy way to override the Host header in the request, so you can only pick the server or the Host, but not both. Luckily, the library allows you to override the HTTP transport class it uses, so you can provide your own. Here’s a transport that seems to work for connecting locally with any given host. It would be fairly easy to modify to connect to any server.

class LocalTransport(xmlrpclib.Transport):
def make_connection(self, host):
self.real_host = host
return xmlrpclib.Transport.make_connection(self, '127.0.0.1')

def send_request(self, connection, handler, request_body):
try:
import gzip
except ImportError:
gzip = None #python can be built without zlib/gzip support
if (self.accept_gzip_encoding and gzip):
connection.putrequest("POST", handler, skip_host=True, skip_accept_encoding=True)
connection.putheader("Accept-Encoding", "gzip")
else:
connection.putrequest("POST", handler, skip_host=True)
connection.putheader("Host", self.real_host)