diff --git a/.distignore b/.distignore
new file mode 100755
index 0000000000000000000000000000000000000000..1649ea423609d218434907825a314314c96c3fa8
--- /dev/null
+++ b/.distignore
@@ -0,0 +1,30 @@
+# 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
+bin
+circle.yml
+composer.json
+composer.lock
+Gruntfile.js
+package.json
+phpunit.xml
+phpunit.xml.dist
+multisite.xml
+multisite.xml.dist
+phpcs.xml
+phpcs.xml.dist
+README.md
+wp-cli.local.yml
+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/.gitignore b/.gitignore
new file mode 100755
index 0000000000000000000000000000000000000000..7b4c57a3988f856fdb2e5688204256b53672c91f
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,7 @@
+.DS_Store
+Thumbs.db
+wp-cli.local.yml
+node_modules/
+*.sql
+*.tar.gz
+*.zip
diff --git a/.travis.yml b/.travis.yml
new file mode 100755
index 0000000000000000000000000000000000000000..a6ccc2eeb7d1ff64145d83a2531fa0a4d8774a3b
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,61 @@
+sudo: false
+
+language: php
+
+notifications:
+  email:
+    on_success: never
+    on_failure: change
+
+cache:
+  directories:
+    - vendor
+    - $HOME/.composer/cache
+
+matrix:
+  include:
+    # PHPUnit
+    - php: 7.2
+      env: WP_VERSION=latest
+    - php: 7.2
+      env: WP_VERSION=trunk
+    - php: 7.1
+      env: WP_VERSION=latest
+    - php: 7.1
+      env: WP_VERSION=trunk
+    - php: 7.0
+      env: WP_VERSION=latest
+    - php: 7.0
+      env: WP_VERSION=trunk
+    # PHPCS
+    - php: 7.1
+      env: WP_TRAVISCI=phpcs
+
+before_script:
+  - phpenv config-rm xdebug.ini
+  - export PATH="$HOME/.composer/vendor/bin:$PATH"
+  - |
+    if [[ ! -z "$WP_VERSION" ]] ; then
+      bash bin/install-wp-tests.sh wordpress_test root '' localhost $WP_VERSION
+      if [[ ${TRAVIS_PHP_VERSION:0:2} == "5." ]]; then
+        composer global require "phpunit/phpunit=4.8.*"
+      else
+        composer global require "phpunit/phpunit=5.7.*"
+      fi
+    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
+    fi
+
+script:
+  - |
+    if [[ ! -z "$WP_VERSION" ]] ; then
+      phpunit
+      WP_MULTISITE=1 phpunit
+    fi
+  - |
+    if [[ "$WP_TRAVISCI" == "phpcs" ]] ; then
+      phpcs
+    fi
diff --git a/Gruntfile.js b/Gruntfile.js
new file mode 100755
index 0000000000000000000000000000000000000000..bc0fcf617a006bdf32648830e622c2c201283693
--- /dev/null
+++ b/Gruntfile.js
@@ -0,0 +1,54 @@
+module.exports = function( grunt ) {
+
+	'use strict';
+	var banner = '/**\n * <%= pkg.homepage %>\n * Copyright (c) <%= grunt.template.today("yyyy") %>\n * This file is generated automatically. Do not edit.\n */\n';
+	// Project configuration
+	grunt.initConfig( {
+
+		pkg: grunt.file.readJSON( 'package.json' ),
+
+		addtextdomain: {
+			options: {
+				textdomain: 'bulk-edit-cron-offload',
+			},
+			update_all_domains: {
+				options: {
+					updateDomains: true
+				},
+				src: [ '*.php', '**/*.php', '!node_modules/**', '!php-tests/**', '!bin/**' ]
+			}
+		},
+
+		wp_readme_to_markdown: {
+			your_target: {
+				files: {
+					'README.md': 'readme.txt'
+				}
+			},
+		},
+
+		makepot: {
+			target: {
+				options: {
+					domainPath: '/languages',
+					mainFile: 'bulk-edit-cron-offload.php',
+					potFilename: 'bulk-edit-cron-offload.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( '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..a23cc6e940f9a903cca83293060ee1a45e9f5bf9
--- /dev/null
+++ b/README.md
@@ -0,0 +1,30 @@
+# Bulk Edit Cron Offload #
+**Contributors:** ethitter, automattic  
+**Tags:** cron, bulk edit  
+**Requires at least:** 4.8.1  
+**Tested up to:** 4.9  
+**Stable tag:** 1.0  
+**License:** GPLv2 or later  
+**License URI:** http://www.gnu.org/licenses/gpl-2.0.html  
+
+Process Core's Bulk Edit requests using Cron
+
+## Description ##
+
+Process Core's Bulk Edit requests using Cron, rather than via a `$_GET` request.
+
+## Installation ##
+
+1. Upload the `bulk-edit-cron-offload` directory to the `/wp-content/plugins/` directory
+1. Activate the plugin through the 'Plugins' menu in WordPress
+
+## Frequently Asked Questions ##
+
+### A question that someone might have ###
+
+An answer to that question.
+
+## Changelog ##
+
+### 1.0 ###
+* Initial release
diff --git a/bin/install-wp-tests.sh b/bin/install-wp-tests.sh
new file mode 100755
index 0000000000000000000000000000000000000000..73bb4c787eb2ccf4b4225729ddaa3578cb606741
--- /dev/null
+++ b/bin/install-wp-tests.sh
@@ -0,0 +1,127 @@
+#!/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}
+
+WP_TESTS_DIR=${WP_TESTS_DIR-/tmp/wordpress-tests-lib}
+WP_CORE_DIR=${WP_CORE_DIR-/tmp/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]+(\.[0-9]+)? ]]; then
+	WP_TESTS_TAG="tags/$WP_VERSION"
+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 /tmp/wordpress-nightly
+		download https://wordpress.org/nightly-builds/wordpress-latest.zip  /tmp/wordpress-nightly/wordpress-nightly.zip
+		unzip -q /tmp/wordpress-nightly/wordpress-nightly.zip -d /tmp/wordpress-nightly/
+		mv /tmp/wordpress-nightly/wordpress/* $WP_CORE_DIR
+	else
+		if [ $WP_VERSION == 'latest' ]; then
+			local ARCHIVE_NAME='latest'
+		else
+			local ARCHIVE_NAME="wordpress-$WP_VERSION"
+		fi
+		download https://wordpress.org/${ARCHIVE_NAME}.tar.gz  /tmp/wordpress.tar.gz
+		tar --strip-components=1 -zxmf /tmp/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/bulk-edit-cron-offload.php b/bulk-edit-cron-offload.php
index 5297a8dd51d0b7f2c0913fd08f89d0230d2c1686..4c3e2552dece2650a094463bba329732e88604b4 100644
--- a/bulk-edit-cron-offload.php
+++ b/bulk-edit-cron-offload.php
@@ -1,17 +1,21 @@
 <?php
-/*
- Plugin Name: Offload Bulk Edit to Cron
- Plugin URI: https://vip.wordpress.com/
- Description: Process Bulk Edit requests using Cron
- Author: Erick Hitter, Automattic
- Version: 1.0
- Text Domain: automattic-bulk-edit-cron-offload
+/**
+ * Plugin Name:     Bulk Edit Cron Offload
+ * Plugin URI:      https://vip.wordpress.com/
+ * Description:     Process Bulk Edit requests using Cron
+ * Author:          Erick Hitter, Automattic
+ * Author URI:      https://automattic.com/
+ * Text Domain:     automattic-bulk-edit-cron-offload
+ * Domain Path:     /languages
+ * Version:         1.0
+ *
+ * @package         Bulk_Edit_Cron_Offload
  */
 
 namespace Automattic\WP\Bulk_Edit_Cron_Offload;
 
-// Plugin dependencies
-require __DIR__ . '/includes/abstract-class-singleton.php';
+// Plugin dependencies.
+require __DIR__ . '/includes/class-singleton.php';
 
-// Plugin functionality
+// Plugin functionality.
 require __DIR__ . '/includes/class-main.php';
diff --git a/includes/class-main.php b/includes/class-main.php
index c9fdb000ed232581deb1ecee2a569fbd0cfe3319..7d44e484eb00e5f58a10638fd1eb0d912c1b4196 100644
--- a/includes/class-main.php
+++ b/includes/class-main.php
@@ -1,50 +1,76 @@
 <?php
+/**
+ * Plugin's main class, dispatcher for specific bulk-edit requests
+ *
+ * @package Bulk_Edit_Cron_Offload
+ */
 
 namespace Automattic\WP\Bulk_Edit_Cron_Offload;
 
+/**
+ * Class Main
+ */
 class Main extends Singleton {
 	/**
 	 * Requested action
+	 *
+	 * @var string
 	 */
 	private $action = null;
 
 	/**
 	 * Posts to process
+	 *
+	 * @var array
 	 */
 	private $posts = null;
 
 	/**
 	 * Taxonomy terms to add
+	 *
+	 * @var array
 	 */
 	private $tax_input = null;
 
 	/**
 	 * Post author to set
+	 *
+	 * @var int
 	 */
 	private $post_author = null;
 
 	/**
 	 * Comment status to set
+	 *
+	 * @var string
 	 */
 	private $comment_status = null;
 
 	/**
 	 * Ping status to set
+	 *
+	 * @var string
 	 */
 	private $ping_status = null;
 
 	/**
 	 * New post status
+	 *
+	 * @var string
 	 */
 	private $post_status = null;
 
 	/**
-	 * Posts' stick status
+	 * Posts' sticky status
+	 *
+	 * @var int
 	 */
 	private $post_sticky = null;
 
 	/**
 	 * Posts' format
+	 *
+	 * @var string
 	 */
 	private $post_format = null;
 
@@ -59,33 +85,33 @@ class Main extends Singleton {
 	 * Call appropriate handler
 	 */
 	public function intercept() {
-		// Nothing to do
+		// Nothing to do.
 		if ( ! isset( $_REQUEST['action'] ) ) {
 			return;
 		}
 
-		// Parse request to determine what to do
+		// Parse request to determine what to do.
 		$this->populate_vars();
 
 		// Now what?
 		switch ( $this->action ) {
-			case 'delete_all' :
+			case 'delete_all':
 				break;
 
-			case 'trash' :
+			case 'trash':
 				break;
 
-			case 'untrash' :
+			case 'untrash':
 				break;
 
-			case 'delete' :
+			case 'delete':
 				break;
 
-			case 'edit' :
+			case 'edit':
 				break;
 
 			// How did you get here?
-			default :
+			default:
 				return;
 				break;
 		}
@@ -129,7 +155,7 @@ class Main extends Singleton {
 			$this->post_format = $_REQUEST['post_format'];
 		}
 
-		// Stop Core from processing bulk request
+		// Stop Core from processing bulk request.
 		unset( $_REQUEST['action'] );
 		unset( $_REQUEST['action2'] );
 	}
diff --git a/includes/abstract-class-singleton.php b/includes/class-singleton.php
similarity index 70%
rename from includes/abstract-class-singleton.php
rename to includes/class-singleton.php
index 5c8042f8b4a3fb97a80c17e81d3a75a2a104482b..53ed87ab65755e26b70fd53644f6e2d3387d6b01 100644
--- a/includes/abstract-class-singleton.php
+++ b/includes/class-singleton.php
@@ -1,13 +1,28 @@
 <?php
+/**
+ * Abstract singleton for plugin's main classes
+ *
+ * @package Bulk_Edit_Cron_Offload
+ */
 
 namespace Automattic\WP\Bulk_Edit_Cron_Offload;
 
+/**
+ * Class Singleton
+ */
 abstract class Singleton {
 	/**
 	 * Class instance
+	 *
+	 * @var array
 	 */
 	private static $__instances = array();
 
+	/**
+	 * Instantiate the class
+	 *
+	 * @return self
+	 */
 	public static function instance() {
 		$caller = get_called_class();
 
@@ -20,6 +35,9 @@ abstract class Singleton {
 		return self::$__instances[ $caller ];
 	}
 
+	/**
+	 * Singleton constructor
+	 */
 	protected function __construct() {}
 
 	/**
diff --git a/languages/bulk-edit-cron-offload.pot b/languages/bulk-edit-cron-offload.pot
new file mode 100644
index 0000000000000000000000000000000000000000..c61a699cf66937b19ba5bdfccdd3bc2e02575ea3
--- /dev/null
+++ b/languages/bulk-edit-cron-offload.pot
@@ -0,0 +1,46 @@
+# Copyright (C) 2017 Erick Hitter, Automattic
+# This file is distributed under the same license as the Bulk Edit Cron Offload package.
+msgid ""
+msgstr ""
+"Project-Id-Version: Bulk Edit Cron Offload 1.0\n"
+"Report-Msgid-Bugs-To: "
+"https://wordpress.org/support/plugin/bulk-edit-cron-offload\n"
+"POT-Creation-Date: 2017-09-13 00:10:57+00:00\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=utf-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"PO-Revision-Date: 2017-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"
+
+#. Plugin Name of the plugin/theme
+msgid "Bulk Edit Cron Offload"
+msgstr ""
+
+#. Plugin URI of the plugin/theme
+msgid "https://vip.wordpress.com/"
+msgstr ""
+
+#. Description of the plugin/theme
+msgid "Process Bulk Edit requests using Cron"
+msgstr ""
+
+#. Author of the plugin/theme
+msgid "Erick Hitter, Automattic"
+msgstr ""
+
+#. Author URI of the plugin/theme
+msgid "https://automattic.com/"
+msgstr ""
\ No newline at end of file
diff --git a/package.json b/package.json
new file mode 100755
index 0000000000000000000000000000000000000000..6696683db036d618026bdf6278b97ccec4207df8
--- /dev/null
+++ b/package.json
@@ -0,0 +1,11 @@
+{
+  "name": "bulk-edit-cron-offload",
+  "version": "0.1.0",
+  "main": "Gruntfile.js",
+  "author": "YOUR NAME HERE",
+  "devDependencies": {
+    "grunt": "~0.4.5",
+    "grunt-wp-i18n": "~0.5.0",
+    "grunt-wp-readme-to-markdown": "~1.0.0"
+  }
+}
diff --git a/phpcs.xml.dist b/phpcs.xml.dist
new file mode 100644
index 0000000000000000000000000000000000000000..2c9e091164834d4505603e2f39ec9a96e193ec8e
--- /dev/null
+++ b/phpcs.xml.dist
@@ -0,0 +1,17 @@
+<?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 sniff codes in all reports -->
+	<arg value="s"/>
+
+	<exclude-pattern>*/node_modules/*</exclude-pattern>
+	<exclude-pattern>*/vendor/*</exclude-pattern>
+</ruleset>
diff --git a/phpunit.xml.dist b/phpunit.xml.dist
new file mode 100644
index 0000000000000000000000000000000000000000..2bff769f357d6564eed7ebf3b12b6cdff5647bc9
--- /dev/null
+++ b/phpunit.xml.dist
@@ -0,0 +1,14 @@
+<phpunit
+	bootstrap="tests/bootstrap.php"
+	backupGlobals="false"
+	colors="true"
+	convertErrorsToExceptions="true"
+	convertNoticesToExceptions="true"
+	convertWarningsToExceptions="true"
+	>
+	<testsuites>
+		<testsuite>
+			<directory suffix=".php">./tests/tests/</directory>
+		</testsuite>
+	</testsuites>
+</phpunit>
diff --git a/readme.txt b/readme.txt
new file mode 100755
index 0000000000000000000000000000000000000000..57472658e428a21d8c58cf0079dabbaf0e047823
--- /dev/null
+++ b/readme.txt
@@ -0,0 +1,30 @@
+=== Bulk Edit Cron Offload ===
+Contributors: ethitter, automattic
+Tags: cron, bulk edit
+Requires at least: 4.8.1
+Tested up to: 4.9
+Stable tag: 1.0
+License: GPLv2 or later
+License URI: http://www.gnu.org/licenses/gpl-2.0.html
+
+Process Core's Bulk Edit requests using Cron
+
+== Description ==
+
+Process Core's Bulk Edit requests using Cron, rather than via a `$_GET` request.
+
+== Installation ==
+
+1. Upload the `bulk-edit-cron-offload` directory to the `/wp-content/plugins/` directory
+1. Activate the plugin through the 'Plugins' menu in WordPress
+
+== Frequently Asked Questions ==
+
+= A question that someone might have =
+
+An answer to that question.
+
+== Changelog ==
+
+= 1.0 =
+* Initial release
diff --git a/tests/bootstrap.php b/tests/bootstrap.php
new file mode 100755
index 0000000000000000000000000000000000000000..dde0131d4f82fcad28438b657a4acec782c8545b
--- /dev/null
+++ b/tests/bootstrap.php
@@ -0,0 +1,25 @@
+<?php
+/**
+ * PHPUnit bootstrap file
+ *
+ * @package Bulk_Edit_Cron_Offload
+ */
+
+$_tests_dir = getenv( 'WP_TESTS_DIR' );
+if ( ! $_tests_dir ) {
+	$_tests_dir = '/tmp/wordpress-tests-lib';
+}
+
+// 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__ ) ) . '/bulk-edit-cron-offload.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/tests/class-sampletest.php b/tests/tests/class-sampletest.php
new file mode 100755
index 0000000000000000000000000000000000000000..814ff7bfb0a76a782a230f37a4c60111ad4bc22f
--- /dev/null
+++ b/tests/tests/class-sampletest.php
@@ -0,0 +1,20 @@
+<?php
+/**
+ * Class SampleTest
+ *
+ * @package Bulk_Edit_Cron_Offload
+ */
+
+/**
+ * Sample test case.
+ */
+class SampleTest extends WP_UnitTestCase {
+
+	/**
+	 * A single example test.
+	 */
+	function test_sample() {
+		// Replace this with some actual testing code.
+		$this->assertTrue( true );
+	}
+}