diff --git a/.gitignore b/.gitignore
index 6f68bc7f65c25ceae8e856eb9ab25fa815acf0cd..63bb990a1793ee5ff8d6a300b46944b26f77b1d0 100755
--- a/.gitignore
+++ b/.gitignore
@@ -1,5 +1,4 @@
 .DS_Store
-phpcs.xml
 phpunit.xml
 Thumbs.db
 wp-cli.local.yml
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
new file mode 100644
index 0000000000000000000000000000000000000000..e9530261221d1863318d1f0574f6592b8aae4001
--- /dev/null
+++ b/.gitlab-ci.yml
@@ -0,0 +1,65 @@
+variables:
+  # Configure mysql service (https://hub.docker.com/_/mysql/)
+  MYSQL_DATABASE: wordpress_tests
+  MYSQL_ROOT_PASSWORD: mysql
+
+cache:
+  paths:
+    - $HOME/.composer
+    - /root/.composer
+
+before_script:
+  # Set up WordPress tests
+  - bash bin/install-wp-tests.sh $MYSQL_DATABASE root $MYSQL_ROOT_PASSWORD mysql latest true
+
+  # PHPUnit
+  - |
+    if [[ $(php -v) =~ "PHP 7." ]]; then
+      composer global require "phpunit/phpunit=6.1.*"
+    else
+      composer global require "phpunit/phpunit=4.8.*"
+    fi
+
+  # Install PHPCS and WPCS
+  - composer global require automattic/vipwpcs
+  - phpcs --config-set installed_paths $HOME/.composer/vendor/wp-coding-standards/wpcs,$HOME/.composer/vendor/automattic/vipwpcs
+
+PHPunit:PHP5.3:MySQL:
+  image: containers.ethitter.com:443/docker/images/php:5.3
+  services:
+    - mysql:5.6
+  script:
+    - phpcs -n
+    - phpunit
+
+PHPunit:PHP5.6:MySQL:
+  image: containers.ethitter.com:443/docker/images/php:5.6
+  services:
+    - mysql:5.6
+  script:
+    - phpcs -n
+    - phpunit
+
+PHPunit:PHP7.0:MySQL:
+  image: containers.ethitter.com:443/docker/images/php:7.0
+  services:
+    - mysql:5.6
+  script:
+    - phpcs -n
+    - phpunit
+
+PHPunit:PHP7.1:MySQL:
+  image: containers.ethitter.com:443/docker/images/php:7.1
+  services:
+    - mysql:5.6
+  script:
+    - phpcs -n
+    - phpunit
+
+PHPunit:PHP7.2:MySQL:
+  image: containers.ethitter.com:443/docker/images/php:7.2
+  services:
+    - mysql:5.6
+  script:
+    - phpcs -n
+    - phpunit
diff --git a/.travis.yml b/.travis.yml
index d2b35d6e3b3d8b0589b3a1a02d9d612cd46d62f4..38e5608e534f0dee4b8520bd1e9a5f0a0d12cb44 100755
--- a/.travis.yml
+++ b/.travis.yml
@@ -46,8 +46,8 @@ before_script:
     fi
   - |
     if [[ "$WP_TRAVISCI" == "phpcs" ]] ; then
-      composer global require wp-coding-standards/wpcs
-      phpcs --config-set installed_paths $HOME/.composer/vendor/wp-coding-standards/wpcs
+      composer global require automattic/vipwpcs
+      phpcs --config-set installed_paths $HOME/.composer/vendor/wp-coding-standards/wpcs,$HOME/.composer/vendor/automattic/vipwpcs
     fi
 
 script:
diff --git a/bin/install-wp-tests.sh b/bin/install-wp-tests.sh
index 878881f0315b397fd3d758752702d4aa45edc8e0..364f83999f95f0cf17ef2696bc74c8f89cbe932a 100755
--- a/bin/install-wp-tests.sh
+++ b/bin/install-wp-tests.sh
@@ -95,7 +95,7 @@ install_wp() {
 install_test_suite() {
 	# portable in-place argument for both GNU sed and Mac OSX sed
 	if [[ $(uname -s) == 'Darwin' ]]; then
-		local ioption='-i .bak'
+		local ioption='-i.bak'
 	else
 		local ioption='-i'
 	fi
diff --git a/phpcs.xml b/phpcs.xml
new file mode 100644
index 0000000000000000000000000000000000000000..86c05ab53a92199225ab233e877ae644e600b141
--- /dev/null
+++ b/phpcs.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0"?>
+<ruleset name="WordPress Coding Standards for Plugins">
+	<description>Generally-applicable sniffs for WordPress plugins</description>
+
+	<!--
+	Pass some flags to PHPCS:
+	 p flag: Show progress of the run.
+	 s flag: Show sniff codes in all reports.
+	-->
+	<arg value="ps" />
+
+	<!-- Only check the PHP files. -->
+	<arg name="extensions" value="php" />
+
+	<!-- Check all files in this directory and the directories below it. -->
+	<file>.</file>
+
+	<!-- Exclude a few directories and autogenerated files. -->
+	<exclude-pattern>*/node_modules/*</exclude-pattern>
+	<exclude-pattern>*/vendor/</exclude-pattern>
+
+	<rule ref="WordPress" />
+	<rule ref="WordPressVIPMinimum" />
+	<!--<rule ref="WordPress-VIP-Go" />-->
+
+	<config name="minimum_supported_wp_version" value="4.9" />
+
+	<rule ref="WordPress.NamingConventions.PrefixAllGlobals">
+		<properties>
+			<property name="prefixes" type="array" value="camo" />
+		</properties>
+	</rule>
+</ruleset>
diff --git a/phpcs.xml.dist b/phpcs.xml.dist
deleted file mode 100644
index 4f1d0e5cf919397d4a3aff507b598e0075b9b047..0000000000000000000000000000000000000000
--- a/phpcs.xml.dist
+++ /dev/null
@@ -1,17 +0,0 @@
-<?xml version="1.0"?>
-<ruleset name="WordPress Coding Standards for Plugins">
-	<description>Generally-applicable sniffs for WordPress plugins</description>
-
-	<rule ref="WordPress-Core" />
-	<rule ref="WordPress-Docs" />
-
-	<!-- Check all PHP files in directory tree by default. -->
-	<arg name="extensions" value="php"/>
-	<file>.</file>
-
-	<!-- Show progress and sniff codes in all reports -->
-	<arg value="ps"/>
-
-	<exclude-pattern>*/node_modules/*</exclude-pattern>
-	<exclude-pattern>*/vendor/*</exclude-pattern>
-</ruleset>
diff --git a/tests/bootstrap.php b/tests/bootstrap.php
index 4e5b3cc05118e55f846186a2136b7dab1d94a65f..94fbfa9bff0a1a5efd1966a18668ff4a21c35107 100755
--- a/tests/bootstrap.php
+++ b/tests/bootstrap.php
@@ -5,27 +5,29 @@
  * @package Camo_Image_Proxy
  */
 
-$_tests_dir = getenv( 'WP_TESTS_DIR' );
+$camo_tests_dir = getenv( 'WP_TESTS_DIR' );
 
-if ( ! $_tests_dir ) {
-	$_tests_dir = rtrim( sys_get_temp_dir(), '/\\' ) . '/wordpress-tests-lib';
+if ( ! $camo_tests_dir ) {
+	$camo_tests_dir = rtrim( sys_get_temp_dir(), '/\\' ) . '/wordpress-tests-lib';
 }
 
-if ( ! file_exists( $_tests_dir . '/includes/functions.php' ) ) {
-	echo "Could not find $_tests_dir/includes/functions.php, have you run bin/install-wp-tests.sh ?" . PHP_EOL;
+if ( ! file_exists( $camo_tests_dir . '/includes/functions.php' ) ) {
+	// @codingStandardsIgnoreStart
+	echo "Could not find $camo_tests_dir/includes/functions.php, have you run bin/install-wp-tests.sh ?" . PHP_EOL; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
+	// @codingStandardsIgnoreEnd
 	exit( 1 );
 }
 
 // Give access to tests_add_filter() function.
-require_once $_tests_dir . '/includes/functions.php';
+require_once $camo_tests_dir . '/includes/functions.php';
 
 /**
  * Manually load the plugin being tested.
  */
-function _manually_load_plugin() {
+function camo_manually_load_plugin() {
 	require dirname( dirname( __FILE__ ) ) . '/camo-image-proxy.php';
 }
-tests_add_filter( 'muplugins_loaded', '_manually_load_plugin' );
+tests_add_filter( 'muplugins_loaded', 'camo_manually_load_plugin' );
 
 // Start up the WP testing environment.
-require $_tests_dir . '/includes/bootstrap.php';
+require $camo_tests_dir . '/includes/bootstrap.php';
diff --git a/tests/test-sample.php b/tests/test-sample.php
index f4e62d1791e546d84193345b8003ff3186c9fdb3..9d79786fb8cd3b3224f4828bcaca0f6a52ba23bd 100755
--- a/tests/test-sample.php
+++ b/tests/test-sample.php
@@ -13,7 +13,7 @@ class SampleTest extends WP_UnitTestCase {
 	/**
 	 * A single example test.
 	 */
-	function test_sample() {
+	public function test_sample() {
 		// Replace this with some actual testing code.
 		$this->assertTrue( true );
 	}