diff --git a/.distignore b/.distignore
new file mode 100755
index 0000000000000000000000000000000000000000..de45f50cb1a7a08e1da5aa43d801213aa7e23503
--- /dev/null
+++ b/.distignore
@@ -0,0 +1,35 @@
+# A set of files you probably don't want in your WordPress.org distribution
+.distignore
+.editorconfig
+.git
+.gitignore
+.gitlab-ci.yml
+.travis.yml
+.DS_Store
+Thumbs.db
+behat.yml
+bitbucket-pipelines.yml
+bin
+.circleci/config.yml
+composer.json
+composer.lock
+Gruntfile.js
+package.json
+package-lock.json
+phpunit.xml
+phpunit.xml.dist
+multisite.xml
+multisite.xml.dist
+.phpcs.xml
+phpcs.xml
+.phpcs.xml.dist
+phpcs.xml.dist
+README.md
+wp-cli.local.yml
+yarn.lock
+tests
+vendor
+node_modules
+*.sql
+*.tar.gz
+*.zip
diff --git a/.editorconfig b/.editorconfig
new file mode 100755
index 0000000000000000000000000000000000000000..79207a40cb9326b8c6b8c958fa864b5345f94e68
--- /dev/null
+++ b/.editorconfig
@@ -0,0 +1,22 @@
+# This file is for unifying the coding style for different editors and IDEs
+# editorconfig.org
+
+# WordPress Coding Standards
+# https://make.wordpress.org/core/handbook/coding-standards/
+
+root = true
+
+[*]
+charset = utf-8
+end_of_line = lf
+insert_final_newline = true
+trim_trailing_whitespace = true
+indent_style = tab
+indent_size = 4
+
+[{.jshintrc,*.json,*.yml}]
+indent_style = space
+indent_size = 2
+
+[{*.txt,wp-config-sample.php}]
+end_of_line = crlf
diff --git a/.gitattributes b/.gitattributes
new file mode 100644
index 0000000000000000000000000000000000000000..d632abe387d802229a8cf427ad99422027490dfe
--- /dev/null
+++ b/.gitattributes
@@ -0,0 +1,35 @@
+# A set of files you probably don't want in your WordPress.org distribution
+/.distignore export-ignore
+/.editorconfig export-ignore
+/.gitattributes export-ignore
+/.gitignore export-ignore
+/.gitlab-ci.yml export-ignore
+/.travis.yml export-ignore
+/.DS_Store export-ignore
+/Thumbs.db export-ignore
+/behat.yml export-ignore
+/bitbucket-pipelines.yml export-ignore
+/bin export-ignore
+/.circleci/config.yml export-ignore
+/composer.json export-ignore
+/composer.lock export-ignore
+/Gruntfile.js export-ignore
+/package.json export-ignore
+/package-lock.json export-ignore
+/phpunit.xml export-ignore
+/phpunit.xml.dist export-ignore
+/multisite.xml export-ignore
+/multisite.xml.dist export-ignore
+/.phpcs.xml export-ignore
+/phpcs.xml export-ignore
+/.phpcs.xml.dist export-ignore
+/phpcs.xml.dist export-ignore
+/README.md export-ignore
+/wp-cli.local.yml export-ignore
+/yarn.lock export-ignore
+/tests export-ignore
+/vendor export-ignore
+/node_modules export-ignore
+/*.sql export-ignore
+/*.tar.gz export-ignore
+/*.zip export-ignore
diff --git a/.gitignore b/.gitignore
new file mode 100755
index 0000000000000000000000000000000000000000..6f68bc7f65c25ceae8e856eb9ab25fa815acf0cd
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,9 @@
+.DS_Store
+phpcs.xml
+phpunit.xml
+Thumbs.db
+wp-cli.local.yml
+node_modules/
+*.sql
+*.tar.gz
+*.zip
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
new file mode 100755
index 0000000000000000000000000000000000000000..40c53b76bbfcdb3b614b4ff21a13d2a52de56d50
--- /dev/null
+++ b/.gitlab-ci.yml
@@ -0,0 +1,57 @@
+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
+  - composer global require phpcompatibility/phpcompatibility-wp
+  - phpcs --config-set installed_paths $HOME/.composer/vendor/wp-coding-standards/wpcs,$HOME/.composer/vendor/automattic/vipwpcs,$HOME/.composer/vendor/phpcompatibility/php-compatibility,$HOME/.composer/vendor/phpcompatibility/phpcompatibility-paragonie,$HOME/.composer/vendor/phpcompatibility/phpcompatibility-wp
+
+PHPunit:PHP7.2:MySQL:
+  stage: test
+  image: containers.ethitter.com:443/docker/images/php:7.2
+  services:
+    - mysql:5.6
+  script:
+    - find . -type "f" -iname "*.php" | xargs -L "1" php -l
+    - phpcs -n
+    - phpunit
+  allow_failure: true
+
+PHPunit:PHP7.3:MySQL:
+  stage: test
+  image: containers.ethitter.com:443/docker/images/php:7.3
+  services:
+    - mysql:5.6
+  script:
+    - find . -type "f" -iname "*.php" | xargs -L "1" php -l
+    - phpcs -n
+    - phpunit
+  allow_failure: true
+
+PluginSVN:
+  stage: deploy
+  image: containers.ethitter.com:443/docker/images/php:7.3
+  before_script:
+    - curl -o ./bin/deploy.sh https://git-cdn.e15r.co/open-source/wp-org-plugin-deploy/raw/master/scripts/deploy.sh
+    - chmod +x ./bin/deploy.sh
+  script: ./bin/deploy.sh
+  when: on_success
diff --git a/.phpcs.xml.dist b/.phpcs.xml.dist
new file mode 100644
index 0000000000000000000000000000000000000000..7dfcb692f269238decac45ae18a1e6a510736005
--- /dev/null
+++ b/.phpcs.xml.dist
@@ -0,0 +1,50 @@
+<?xml version="1.0"?>
+<ruleset name="ETH Simple Shortlinks">
+	<description>Generally-applicable sniffs for WordPress plugins.</description>
+
+	<!-- What to scan -->
+	<file>.</file>
+	<exclude-pattern>/vendor/</exclude-pattern>
+	<exclude-pattern>/node_modules/</exclude-pattern>
+	<exclude-pattern>/tests/*</exclude-pattern>
+
+	<!-- How to scan -->
+	<!-- Usage instructions: https://github.com/squizlabs/PHP_CodeSniffer/wiki/Usage -->
+	<!-- Annotated ruleset: https://github.com/squizlabs/PHP_CodeSniffer/wiki/Annotated-ruleset.xml -->
+	<arg value="sp"/> <!-- Show sniff and progress -->
+	<arg name="basepath" value="./"/><!-- Strip the file paths down to the relevant bit -->
+	<arg name="colors"/>
+	<arg name="extensions" value="php"/>
+	<arg name="parallel" value="8"/><!-- Enables parallel processing when available for faster results. -->
+
+	<!-- Rules: Check PHP version compatibility -->
+	<!-- https://github.com/PHPCompatibility/PHPCompatibility#sniffing-your-code-for-compatibility-with-specific-php-versions -->
+	<config name="testVersion" value="7.2-"/>
+	<!-- https://github.com/PHPCompatibility/PHPCompatibilityWP -->
+	<rule ref="PHPCompatibilityWP"/>
+
+	<!-- Rules: WordPress Coding Standards -->
+	<!-- https://github.com/WordPress-Coding-Standards/WordPress-Coding-Standards -->
+	<!-- https://github.com/WordPress-Coding-Standards/WordPress-Coding-Standards/wiki/Customizable-sniff-properties -->
+	<config name="minimum_supported_wp_version" value="3.2.1"/>
+	<rule ref="WordPress" />
+	<rule ref="WordPressVIPMinimum" />
+	<rule ref="WordPress-VIP-Go" />
+	<rule ref="WordPress.NamingConventions.PrefixAllGlobals">
+		<properties>
+			<!-- Value: replace the function, class, and variable prefixes used. Separate multiple prefixes with a comma. -->
+			<property name="prefixes" type="array" value="eth_simple_shortlinks"/>
+		</properties>
+	</rule>
+	<rule ref="WordPress.WP.I18n">
+		<properties>
+			<!-- Value: replace the text domain used. -->
+			<property name="text_domain" type="array" value="eth_simple_shortlinks"/>
+		</properties>
+	</rule>
+	<rule ref="WordPress.WhiteSpace.ControlStructureSpacing">
+		<properties>
+			<property name="blank_line_check" value="true"/>
+		</properties>
+	</rule>
+</ruleset>
diff --git a/Gruntfile.js b/Gruntfile.js
new file mode 100755
index 0000000000000000000000000000000000000000..3d3f1d29edbd711a8e509a0188282202201fd5f0
--- /dev/null
+++ b/Gruntfile.js
@@ -0,0 +1,56 @@
+module.exports = function( grunt ) {
+
+	'use strict';
+
+	// Project configuration
+	grunt.initConfig( {
+
+		pkg: grunt.file.readJSON( 'package.json' ),
+
+		addtextdomain: {
+			options: {
+				textdomain: 'eth_simple_shortlinks',
+			},
+			update_all_domains: {
+				options: {
+					updateDomains: true
+				},
+				src: [ '*.php', '**/*.php', '!\.git/**/*', '!bin/**/*', '!node_modules/**/*', '!tests/**/*' ]
+			}
+		},
+
+		wp_readme_to_markdown: {
+			your_target: {
+				files: {
+					'README.md': 'readme.txt'
+				}
+			},
+		},
+
+		makepot: {
+			target: {
+				options: {
+					domainPath: '/languages',
+					exclude: [ '\.git/*', 'bin/*', 'node_modules/*', 'tests/*' ],
+					mainFile: 'eth-simple-shortlinks.php',
+					potFilename: 'eth-simple-shortlinks.pot',
+					potHeaders: {
+						poedit: true,
+						'x-poedit-keywordslist': true
+					},
+					type: 'wp-plugin',
+					updateTimestamp: true
+				}
+			}
+		},
+	} );
+
+	grunt.loadNpmTasks( 'grunt-wp-i18n' );
+	grunt.loadNpmTasks( 'grunt-wp-readme-to-markdown' );
+	grunt.registerTask( 'default', [ 'i18n','readme' ] );
+	grunt.registerTask( 'i18n', ['addtextdomain', 'makepot'] );
+	grunt.registerTask( 'readme', ['wp_readme_to_markdown'] );
+
+	grunt.util.linefeed = '\n';
+
+};
diff --git a/README.md b/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..a9166e400919ee66468366d3d72dda5e6a2bc899
--- /dev/null
+++ b/README.md
@@ -0,0 +1,41 @@
+# ETH Simple Shortlinks #
+**Contributors:** ethitter  
+**Donate link:** https://ethitter.com/donate/  
+**Tags:** seo, meta tags  
+**Requires at least:** 4.4  
+**Tested up to:** 5.2  
+**Stable tag:** 0.5  
+**License:** GPLv2 or later  
+**License URI:** http://www.gnu.org/licenses/gpl-2.0.html  
+
+Convert WordPress's query-based shortlinks to pretty permalinks that are cacheable. http://example.com/?p=123 becomes http://example.com/p/123/.
+
+## Description ##
+
+WordPress 3.0 introduced a native shortlinks feature, which builds URLs using query strings. This plugin converts those URLs to ones using pretty permalinks, which makes for a nicer-looking URL and improves shortlinks' ability to be cached.
+
+Posts and pages are supported by default, while filters make it possible to support other post types.
+
+For example, http://example.com/?p=123 becomes http://example.com/p/123/.
+
+## Installation ##
+
+1. Upload the plugin files to the `/wp-content/plugins/eth-simple-shortlinks` directory, or install the plugin through the WordPress plugins screen directly.
+1. Activate the plugin through the 'Plugins' screen in WordPress.
+1. Flush your site's rewrite rules by visiting Settings > Permalinks.
+
+## Frequently Asked Questions ##
+
+### Can I customize a shortlink? ###
+
+No, shortlinks use the posts' IDs, so aren't available for modification.
+
+## Changelog ##
+
+### 0.5 ###
+* Admin notices when permalinks won't support the plugin
+* Disable plugin functionality when permalink structure is incompatible
+* Translation support
+
+### 0.4 ###
+* Initial release
diff --git a/bin/install-wp-tests.sh b/bin/install-wp-tests.sh
new file mode 100755
index 0000000000000000000000000000000000000000..5ceac4b84b4d05ad6b3525cc9d8b2fd055c32554
--- /dev/null
+++ b/bin/install-wp-tests.sh
@@ -0,0 +1,155 @@
+#!/usr/bin/env bash
+
+if [ $# -lt 3 ]; then
+	echo "usage: $0 <db-name> <db-user> <db-pass> [db-host] [wp-version] [skip-database-creation]"
+	exit 1
+fi
+
+DB_NAME=$1
+DB_USER=$2
+DB_PASS=$3
+DB_HOST=${4-localhost}
+WP_VERSION=${5-latest}
+SKIP_DB_CREATE=${6-false}
+
+TMPDIR=${TMPDIR-/tmp}
+TMPDIR=$(echo $TMPDIR | sed -e "s/\/$//")
+WP_TESTS_DIR=${WP_TESTS_DIR-$TMPDIR/wordpress-tests-lib}
+WP_CORE_DIR=${WP_CORE_DIR-$TMPDIR/wordpress/}
+
+download() {
+    if [ `which curl` ]; then
+        curl -s "$1" > "$2";
+    elif [ `which wget` ]; then
+        wget -nv -O "$2" "$1"
+    fi
+}
+
+if [[ $WP_VERSION =~ ^[0-9]+\.[0-9]+\-(beta|RC)[0-9]+$ ]]; then
+	WP_BRANCH=${WP_VERSION%\-*}
+	WP_TESTS_TAG="branches/$WP_BRANCH"
+
+elif [[ $WP_VERSION =~ ^[0-9]+\.[0-9]+$ ]]; then
+	WP_TESTS_TAG="branches/$WP_VERSION"
+elif [[ $WP_VERSION =~ [0-9]+\.[0-9]+\.[0-9]+ ]]; then
+	if [[ $WP_VERSION =~ [0-9]+\.[0-9]+\.[0] ]]; then
+		# version x.x.0 means the first release of the major version, so strip off the .0 and download version x.x
+		WP_TESTS_TAG="tags/${WP_VERSION%??}"
+	else
+		WP_TESTS_TAG="tags/$WP_VERSION"
+	fi
+elif [[ $WP_VERSION == 'nightly' || $WP_VERSION == 'trunk' ]]; then
+	WP_TESTS_TAG="trunk"
+else
+	# http serves a single offer, whereas https serves multiple. we only want one
+	download http://api.wordpress.org/core/version-check/1.7/ /tmp/wp-latest.json
+	grep '[0-9]+\.[0-9]+(\.[0-9]+)?' /tmp/wp-latest.json
+	LATEST_VERSION=$(grep -o '"version":"[^"]*' /tmp/wp-latest.json | sed 's/"version":"//')
+	if [[ -z "$LATEST_VERSION" ]]; then
+		echo "Latest WordPress version could not be found"
+		exit 1
+	fi
+	WP_TESTS_TAG="tags/$LATEST_VERSION"
+fi
+set -ex
+
+install_wp() {
+
+	if [ -d $WP_CORE_DIR ]; then
+		return;
+	fi
+
+	mkdir -p $WP_CORE_DIR
+
+	if [[ $WP_VERSION == 'nightly' || $WP_VERSION == 'trunk' ]]; then
+		mkdir -p $TMPDIR/wordpress-nightly
+		download https://wordpress.org/nightly-builds/wordpress-latest.zip  $TMPDIR/wordpress-nightly/wordpress-nightly.zip
+		unzip -q $TMPDIR/wordpress-nightly/wordpress-nightly.zip -d $TMPDIR/wordpress-nightly/
+		mv $TMPDIR/wordpress-nightly/wordpress/* $WP_CORE_DIR
+	else
+		if [ $WP_VERSION == 'latest' ]; then
+			local ARCHIVE_NAME='latest'
+		elif [[ $WP_VERSION =~ [0-9]+\.[0-9]+ ]]; then
+			# https serves multiple offers, whereas http serves single.
+			download https://api.wordpress.org/core/version-check/1.7/ $TMPDIR/wp-latest.json
+			if [[ $WP_VERSION =~ [0-9]+\.[0-9]+\.[0] ]]; then
+				# version x.x.0 means the first release of the major version, so strip off the .0 and download version x.x
+				LATEST_VERSION=${WP_VERSION%??}
+			else
+				# otherwise, scan the releases and get the most up to date minor version of the major release
+				local VERSION_ESCAPED=`echo $WP_VERSION | sed 's/\./\\\\./g'`
+				LATEST_VERSION=$(grep -o '"version":"'$VERSION_ESCAPED'[^"]*' $TMPDIR/wp-latest.json | sed 's/"version":"//' | head -1)
+			fi
+			if [[ -z "$LATEST_VERSION" ]]; then
+				local ARCHIVE_NAME="wordpress-$WP_VERSION"
+			else
+				local ARCHIVE_NAME="wordpress-$LATEST_VERSION"
+			fi
+		else
+			local ARCHIVE_NAME="wordpress-$WP_VERSION"
+		fi
+		download https://wordpress.org/${ARCHIVE_NAME}.tar.gz  $TMPDIR/wordpress.tar.gz
+		tar --strip-components=1 -zxmf $TMPDIR/wordpress.tar.gz -C $WP_CORE_DIR
+	fi
+
+	download https://raw.github.com/markoheijnen/wp-mysqli/master/db.php $WP_CORE_DIR/wp-content/db.php
+}
+
+install_test_suite() {
+	# portable in-place argument for both GNU sed and Mac OSX sed
+	if [[ $(uname -s) == 'Darwin' ]]; then
+		local ioption='-i.bak'
+	else
+		local ioption='-i'
+	fi
+
+	# set up testing suite if it doesn't yet exist
+	if [ ! -d $WP_TESTS_DIR ]; then
+		# set up testing suite
+		mkdir -p $WP_TESTS_DIR
+		svn co --quiet https://develop.svn.wordpress.org/${WP_TESTS_TAG}/tests/phpunit/includes/ $WP_TESTS_DIR/includes
+		svn co --quiet https://develop.svn.wordpress.org/${WP_TESTS_TAG}/tests/phpunit/data/ $WP_TESTS_DIR/data
+	fi
+
+	if [ ! -f wp-tests-config.php ]; then
+		download https://develop.svn.wordpress.org/${WP_TESTS_TAG}/wp-tests-config-sample.php "$WP_TESTS_DIR"/wp-tests-config.php
+		# remove all forward slashes in the end
+		WP_CORE_DIR=$(echo $WP_CORE_DIR | sed "s:/\+$::")
+		sed $ioption "s:dirname( __FILE__ ) . '/src/':'$WP_CORE_DIR/':" "$WP_TESTS_DIR"/wp-tests-config.php
+		sed $ioption "s/youremptytestdbnamehere/$DB_NAME/" "$WP_TESTS_DIR"/wp-tests-config.php
+		sed $ioption "s/yourusernamehere/$DB_USER/" "$WP_TESTS_DIR"/wp-tests-config.php
+		sed $ioption "s/yourpasswordhere/$DB_PASS/" "$WP_TESTS_DIR"/wp-tests-config.php
+		sed $ioption "s|localhost|${DB_HOST}|" "$WP_TESTS_DIR"/wp-tests-config.php
+	fi
+
+}
+
+install_db() {
+
+	if [ ${SKIP_DB_CREATE} = "true" ]; then
+		return 0
+	fi
+
+	# parse DB_HOST for port or socket references
+	local PARTS=(${DB_HOST//\:/ })
+	local DB_HOSTNAME=${PARTS[0]};
+	local DB_SOCK_OR_PORT=${PARTS[1]};
+	local EXTRA=""
+
+	if ! [ -z $DB_HOSTNAME ] ; then
+		if [ $(echo $DB_SOCK_OR_PORT | grep -e '^[0-9]\{1,\}$') ]; then
+			EXTRA=" --host=$DB_HOSTNAME --port=$DB_SOCK_OR_PORT --protocol=tcp"
+		elif ! [ -z $DB_SOCK_OR_PORT ] ; then
+			EXTRA=" --socket=$DB_SOCK_OR_PORT"
+		elif ! [ -z $DB_HOSTNAME ] ; then
+			EXTRA=" --host=$DB_HOSTNAME --protocol=tcp"
+		fi
+	fi
+
+	# create database
+	mysqladmin create $DB_NAME --user="$DB_USER" --password="$DB_PASS"$EXTRA
+}
+
+install_wp
+install_test_suite
+install_db
diff --git a/eth-simple-shortlinks.php b/eth-simple-shortlinks.php
index a67b05c9d904b335aa9694bed9cb7f96b545d292..381f07d0915d3884d4b50ff4aca5348c4495181a 100644
--- a/eth-simple-shortlinks.php
+++ b/eth-simple-shortlinks.php
@@ -48,8 +48,8 @@ class ETH_Simple_Shortlinks {
 	/**
 	 * Dummy magic methods
 	 */
-	public function __clone() { _doing_it_wrong( __FUNCTION__, __( 'Cheatin&#8217; uh?' ), '0.1' ); }
-	public function __wakeup() { _doing_it_wrong( __FUNCTION__, __( 'Cheatin&#8217; uh?' ), '0.1' ); }
+	public function __clone() { _doing_it_wrong( __FUNCTION__, __( 'Cheatin&#8217; uh?', 'eth_simple_shortlinks' ), '0.1' ); }
+	public function __wakeup() { _doing_it_wrong( __FUNCTION__, __( 'Cheatin&#8217; uh?', 'eth_simple_shortlinks' ), '0.1' ); }
 	public function __call( $name = '', $args = array() ) { unset( $name, $args ); return null; }
 
 	/**
@@ -248,7 +248,7 @@ class ETH_Simple_Shortlinks {
 			return $actions;
 		}
 
-		$actions['shortlink'] = '<a href="' . esc_js( $this->get_shortlink( $post->ID ) ) . '">' . __( 'Shortlink' ) . '</a>';
+		$actions['shortlink'] = '<a href="' . esc_js( $this->get_shortlink( $post->ID ) ) . '">' . __( 'Shortlink', 'eth_simple_shortlinks' ) . '</a>';
 
 		return $actions;
 	}
diff --git a/languages/.gitkeep b/languages/.gitkeep
deleted file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000
diff --git a/languages/eth-simple-shortlinks.pot b/languages/eth-simple-shortlinks.pot
new file mode 100644
index 0000000000000000000000000000000000000000..bf9b3a5f7cec79430b85db643333b98b4e8b850a
--- /dev/null
+++ b/languages/eth-simple-shortlinks.pot
@@ -0,0 +1,76 @@
+# Copyright (C) 2019 Erick Hitter
+# This file is distributed under the same license as the ETH Simple Shortlinks package.
+msgid ""
+msgstr ""
+"Project-Id-Version: ETH Simple Shortlinks 0.5\n"
+"Report-Msgid-Bugs-To: "
+"https://wordpress.org/support/plugin/eth-simple-shortlinks\n"
+"POT-Creation-Date: 2019-04-14 04:31:11+00:00\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=utf-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"PO-Revision-Date: 2019-MO-DA HO:MI+ZONE\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"X-Generator: grunt-wp-i18n 0.5.4\n"
+"X-Poedit-KeywordsList: "
+"__;_e;_x:1,2c;_ex:1,2c;_n:1,2;_nx:1,2,4c;_n_noop:1,2;_nx_noop:1,2,3c;esc_"
+"attr__;esc_html__;esc_attr_e;esc_html_e;esc_attr_x:1,2c;esc_html_x:1,2c;\n"
+"Language: en\n"
+"Plural-Forms: nplurals=2; plural=(n != 1);\n"
+"X-Poedit-Country: United States\n"
+"X-Poedit-SourceCharset: UTF-8\n"
+"X-Poedit-Basepath: ../\n"
+"X-Poedit-SearchPath-0: .\n"
+"X-Poedit-Bookmarks: \n"
+"X-Textdomain-Support: yes\n"
+
+#: eth-simple-shortlinks.php:51 eth-simple-shortlinks.php:52
+msgid "Cheatin&#8217; uh?"
+msgstr ""
+
+#: eth-simple-shortlinks.php:138
+msgid ""
+"Please visit the <a href=\"%1$s\">Permalinks</a> settings page to refresh "
+"your permalinks. Doing so will add the rules this plugin requires."
+msgstr ""
+
+#: eth-simple-shortlinks.php:141
+msgid ""
+"Please enable <a href=\"%1$s\">pretty permalinks</a>, otherwise disable "
+"this plugin as it is not compatible with \"Plain\" permalinks."
+msgstr ""
+
+#: eth-simple-shortlinks.php:146
+msgid "<strong>%1$s</strong>: %2$s"
+msgstr ""
+
+#: eth-simple-shortlinks.php:251
+msgid "Shortlink"
+msgstr ""
+
+#: eth-simple-shortlinks.php:293
+msgid ""
+"Shortlinks cannot be generated until after <code>wp_loaded</code>; this "
+"ensures that all post types are registered."
+msgstr ""
+
+#. Plugin Name of the plugin/theme
+msgid "ETH Simple Shortlinks"
+msgstr ""
+
+#. Plugin URI of the plugin/theme
+msgid "https://ethitter.com/plugins/"
+msgstr ""
+
+#. Description of the plugin/theme
+msgid "Simple non-GET shortlinks using post IDs"
+msgstr ""
+
+#. Author of the plugin/theme
+msgid "Erick Hitter"
+msgstr ""
+
+#. Author URI of the plugin/theme
+msgid "https://ethitter.com/"
+msgstr ""
\ No newline at end of file
diff --git a/package.json b/package.json
new file mode 100755
index 0000000000000000000000000000000000000000..25445df46306bd7c2eb4aec445caaa31952a588b
--- /dev/null
+++ b/package.json
@@ -0,0 +1,11 @@
+{
+  "name": "eth-simple-shortlinks",
+  "version": "0.1.0",
+  "main": "Gruntfile.js",
+  "author": "Erick Hitter",
+  "devDependencies": {
+    "grunt": "~0.4.5",
+    "grunt-wp-i18n": "~0.5.0",
+    "grunt-wp-readme-to-markdown": "~1.0.0"
+  }
+}
diff --git a/phpunit.xml.dist b/phpunit.xml.dist
new file mode 100644
index 0000000000000000000000000000000000000000..16a39027e72be2cf0a2656056074b6e6ed818be1
--- /dev/null
+++ b/phpunit.xml.dist
@@ -0,0 +1,16 @@
+<?xml version="1.0"?>
+<phpunit
+	bootstrap="tests/bootstrap.php"
+	backupGlobals="false"
+	colors="true"
+	convertErrorsToExceptions="true"
+	convertNoticesToExceptions="true"
+	convertWarningsToExceptions="true"
+	>
+	<testsuites>
+		<testsuite>
+			<directory prefix="test-" suffix=".php">./tests/</directory>
+			<exclude>./tests/test-sample.php</exclude>
+		</testsuite>
+	</testsuites>
+</phpunit>
diff --git a/readme.txt b/readme.txt
index 6403d8065ac172f2870f775c4e78074e173faf15..5c47f052e0e907f0fb4f4d5fcd4156b2397399d0 100644
--- a/readme.txt
+++ b/readme.txt
@@ -3,7 +3,7 @@ Contributors: ethitter
 Donate link: https://ethitter.com/donate/
 Tags: seo, meta tags
 Requires at least: 4.4
-Tested up to: 4.6
+Tested up to: 5.2
 Stable tag: 0.5
 License: GPLv2 or later
 License URI: http://www.gnu.org/licenses/gpl-2.0.html
diff --git a/tests/bootstrap.php b/tests/bootstrap.php
new file mode 100755
index 0000000000000000000000000000000000000000..f40e77271f4e5330b21b07efd0341ac3fb7abf57
--- /dev/null
+++ b/tests/bootstrap.php
@@ -0,0 +1,31 @@
+<?php
+/**
+ * PHPUnit bootstrap file
+ *
+ * @package ETH_Simple_Shortlinks
+ */
+
+$_tests_dir = getenv( 'WP_TESTS_DIR' );
+
+if ( ! $_tests_dir ) {
+	$_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; // WPCS: XSS ok.
+	exit( 1 );
+}
+
+// Give access to tests_add_filter() function.
+require_once $_tests_dir . '/includes/functions.php';
+
+/**
+ * Manually load the plugin being tested.
+ */
+function _manually_load_plugin() {
+	require dirname( dirname( __FILE__ ) ) . '/eth-simple-shortlinks.php';
+}
+tests_add_filter( 'muplugins_loaded', '_manually_load_plugin' );
+
+// Start up the WP testing environment.
+require $_tests_dir . '/includes/bootstrap.php';
diff --git a/tests/test-sample.php b/tests/test-sample.php
new file mode 100755
index 0000000000000000000000000000000000000000..d2da28996e7c1ae676df62c9fd21fc2459aa7e15
--- /dev/null
+++ b/tests/test-sample.php
@@ -0,0 +1,20 @@
+<?php
+/**
+ * Class SampleTest
+ *
+ * @package ETH_Simple_Shortlinks
+ */
+
+/**
+ * Sample test case.
+ */
+class SampleTest extends WP_UnitTestCase {
+
+	/**
+	 * A single example test.
+	 */
+	public function test_sample() {
+		// Replace this with some actual testing code.
+		$this->assertTrue( true );
+	}
+}