diff --git .github/workflows/coding-standards.yml .github/workflows/coding-standards.yml
new file mode 100644
index 000000000..ba8e1f042
--- /dev/null
+++ .github/workflows/coding-standards.yml
@@ -0,0 +1,49 @@
+name: Coding Standards
+
+on:
+  push:
+  branches: [ master ]
+
+jobs:
+  phpcs:
+    name: PHPCS
+    runs-on: ubuntu-latest
+    strategy:
+      fail-fast: true
+      matrix:
+        php: ['7.4']
+
+    steps:
+      - name: Cancel previous runs of this workflow
+        uses: styfle/cancel-workflow-action@0.5.0
+        with:
+          access_token: ${{ github.token }}
+
+      - name: Checkout code
+        uses: actions/checkout@v2
+
+      - name: Setup PHP
+        uses: shivammathur/setup-php@v2
+        with:
+          php-version: ${{ matrix.php }}
+          tools: composer:v2
+          coverage: none
+
+      - name: Log information
+        run: |
+          echo "$GITHUB_REF"
+          echo "$GITHUB_EVENT_NAME"
+          git --version
+          php --version
+          composer --version
+
+      - name: Validate Composer
+        run: composer validate --strict
+
+      - name: Install dependencies
+        uses: ramsey/composer-install@v1
+        with:
+          composer-options: "--ignore-platform-reqs"
+
+      - name: Run PHPCS
+        run: composer phpcs
diff --git .github/workflows/unit-tests.yml .github/workflows/unit-tests.yml
new file mode 100644
index 000000000..213eb2b8f
--- /dev/null
+++ .github/workflows/unit-tests.yml
@@ -0,0 +1,96 @@
+name: Unit Tests
+
+on:
+  push:
+  branches: [ master ]
+
+jobs:
+  tests:
+    name: "WP: ${{ matrix.wp_version }} - PHP: ${{ matrix.php }}"
+    runs-on: ubuntu-latest
+    strategy:
+      fail-fast: false
+      matrix:
+        php: ['7.4', '8.0']
+        wp_version: ['master']
+        include:
+          - php: '8.0'
+            wp_version: '5.7'
+          - php: '7.4'
+            wp_version: '5.7'
+    env:
+      WP_ENV_PHP_VERSION: ${{ matrix.php }}
+      WP_VERSION: ${{ matrix.wp_version }}
+
+    steps:
+      - name: Cancel previous runs of this workflow
+        uses: styfle/cancel-workflow-action@0.5.0
+        with:
+          access_token: ${{ github.token }}
+
+      - name: Checkout repository
+        uses: actions/checkout@v2
+
+      - name: Setup PHP
+        uses: shivammathur/setup-php@v2
+        with:
+          php-version: ${{ matrix.php }}
+          tools: composer:v2
+          coverage: none
+
+      - name: Log information
+        run: |
+          echo "$GITHUB_REF"
+          echo "$GITHUB_EVENT_NAME"
+          npm --version
+          node --version
+          git --version
+          php --version
+          composer --version
+
+      - name: Validate Composer
+        run: composer validate --strict
+
+      - name: Install Composer dependencies
+        uses: ramsey/composer-install@v1
+        with:
+          composer-options: "--ignore-platform-reqs"
+
+      - name: Cache node modules
+        uses: actions/cache@v2
+        env:
+          cache-name: cache-node-modules
+        with:
+          # npm cache files are stored in `~/.npm` on Linux/macOS
+          path: ~/.npm
+          key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('**/package-lock.json') }}
+          restore-keys: |
+            ${{ runner.os }}-build-${{ env.cache-name }}-
+            ${{ runner.os }}-build-
+            ${{ runner.os }}-
+
+      - name: Validate node modules
+        run: if [[ -f package.json ]]; then npm audit --audit-level=high --production --cache ~/.npm; fi
+
+      - name: Install node modules
+        run: npm ci --cache ~/.npm
+
+      - name: Setup WordPress
+        run: echo "{\"core\":\"WordPress/WordPress#${WP_VERSION}\"}" >> .wp-env.override.json
+
+      - name: Install WordPress
+        run: |
+          chmod -R 767 ./
+          npm run wp-env start -- --update
+
+      - name: Running single site unit tests
+        run: npm run test-php
+        if: ${{ success() || failure() }}
+
+      - name: Running multi site unit tests
+        run: npm run test-php-multisite
+        if: ${{ success() || failure() }}
+
+      - name: Stop Docker environment
+        run: npm run wp-env stop
+        if: ${{ success() || failure() }}
diff --git .gitignore .gitignore
index cc3f92c79..a08f6858b 100644
--- .gitignore
+++ .gitignore
@@ -26,3 +26,6 @@ build
 
 # The custom Docker config file.
 .wp-env.override.json
+
+# Cache files
+.phpcs/*.json
diff --git .phpcs/.gitkeep .phpcs/.gitkeep
new file mode 100644
index 000000000..38955e325
--- /dev/null
+++ .phpcs/.gitkeep
@@ -0,0 +1 @@
+# This directory can't be empty.
diff --git composer.json composer.json
index 3bf5b45c3..d936760ee 100644
--- composer.json
+++ composer.json
@@ -33,7 +33,12 @@
 	"require-dev": {
 		"phpcompatibility/phpcompatibility-wp": "^2.1.0",
 		"dealerdirect/phpcodesniffer-composer-installer": "^0.7.1",
+		"squizlabs/php_codesniffer" : "^3.5.4",
+		"wp-coding-standards/wpcs": "*",
 		"wp-phpunit/wp-phpunit": "^5.6",
 		"phpunit/phpunit": "^7.5"
+	},
+	"scripts": {
+		"phpcs" : "phpcs . --basepath=."
 	}
 }
diff --git package.json package.json
index 13a9f6cc5..74ffdb363 100644
--- package.json
+++ package.json
@@ -5,10 +5,10 @@
 	},
 	"description": "BuddyPress adds community features to WordPress. Member Profiles, Activity Streams, Direct Messaging, Notifications, and more!",
 	"devDependencies": {
-		"@babel/core": "^7.11.6",
-		"@wordpress/babel-preset-default": "^5.0.1",
+		"@babel/core": "~7.13.14",
+		"@wordpress/babel-preset-default": "~5.1.0",
 		"@wordpress/browserslist-config": "~3.0.1",
-		"@wordpress/env": "^3.0.2",
+		"@wordpress/env": "^4.0.0",
 		"autoprefixer": "~8.5.2",
 		"grunt": "~1.3.0",
 		"grunt-check-dependencies": "~1.0.0",
@@ -18,19 +18,19 @@
 		"grunt-contrib-cssmin": "^3.0.0",
 		"grunt-contrib-imagemin": "~4.0.0",
 		"grunt-contrib-jshint": "^2.1.0",
-		"grunt-contrib-uglify": "^5.0.0",
+		"grunt-contrib-uglify": "~5.0.1",
 		"grunt-contrib-watch": "~1.1.0",
 		"grunt-exec": "^3.0.0",
 		"grunt-jsvalidate": "~0.2.2",
 		"grunt-legacy-util": "^2.0.0",
-		"grunt-patch-wordpress": "~3.0.0",
+		"grunt-patch-wordpress": "~3.0.1",
 		"grunt-postcss": "~0.9.0",
-		"grunt-rtlcss": "~2.0.1",
+		"grunt-rtlcss": "~2.0.2",
 		"grunt-sass": "~2.0.0",
 		"grunt-stylelint": "~0.15.0",
 		"matchdep": "~2.0.0",
-		"parcel-bundler": "~1.12.4",
-		"phplint": "^2.0.1",
+		"parcel-bundler": "~1.12.5",
+		"phplint": "~2.0.5",
 		"postcss-scss": "~2.0.0",
 		"stylelint": "~13.6.1",
 		"stylelint-config-wordpress": "~17.0.0"
@@ -74,6 +74,6 @@
 		"extends @wordpress/browserslist-config"
 	],
 	"dependencies": {
-		"postcss": "~7.0.32"
+		"postcss": "~7.0.35"
 	}
 }
diff --git phpcs.xml.dist phpcs.xml.dist
new file mode 100644
index 000000000..b206b6501
--- /dev/null
+++ phpcs.xml.dist
@@ -0,0 +1,62 @@
+<?xml version="1.0"?>
+<ruleset xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" name="BuddyPress" xsi:noNamespaceSchemaLocation="https://raw.githubusercontent.com/squizlabs/PHP_CodeSniffer/master/phpcs.xsd">
+	<description>PHP_CodeSniffer standard for the BuddyPress plugin.</description>
+
+	<!-- Load WordPress standards -->
+	<rule ref="WordPress"/>
+
+	<!-- Load PHPCompatibilityWP standards -->
+	<rule ref="PHPCompatibilityWP" />
+
+	<!-- Configure the PHP version -->
+	<config name="testVersion" value="5.6-"/>
+
+	<!-- Check against minimum WP version. -->
+	<config name="minimum_supported_wp_version" value="4.9"/>
+
+	<!-- Don't fail CI build on warnings. -->
+	<config name="ignore_warnings_on_exit" value="1"/>
+
+	<!--
+	Pass some flags to PHPCS:
+	p flag: Show progress of the run.
+	s flag: Show sniff codes in all reports.
+	-->
+	<arg value="ps" />
+
+	<!-- Enable colors in report -->
+	<arg name="colors"/>
+
+	<!-- Cache the scan results and re-use those for unchanged files on the next scan. -->
+	<arg name="cache" value=".phpcs/cache.json" />
+
+	<!-- Check 20 files in parallel. -->
+	<arg name="parallel" value="20"/>
+
+	<!-- Set severity to 1 to see everything that isn't effectively turned off. -->
+	<arg name="severity" value="6" />
+
+	<!-- PHP files only, for now. -->
+	<arg name="extensions" value="php" />
+
+	<!-- What to exclude -->
+	<exclude-pattern>*/**/tests/</exclude-pattern>
+	<exclude-pattern>*/node_modules/*</exclude-pattern>
+	<exclude-pattern>*/vendor/*</exclude-pattern>
+
+	<!-- What to exclude from the plugin -->
+	<exclude-pattern>*/**/**/deprecated/*</exclude-pattern>
+
+	<rule ref="WordPress.WP.I18n">
+		<properties>
+			<property name="text_domain" type="array">
+				<element value="buddypress" />
+			</property>
+		</properties>
+	</rule>
+
+	<!-- Allow array disalignment -->
+	<rule ref="WordPress">
+		<exclude name="WordPress.Arrays.MultipleStatementAlignment.DoubleArrowNotAligned"/>
+	</rule>
+</ruleset>
diff --git tests/phpunit/assets/phpunit-wp-config.php tests/phpunit/assets/phpunit-wp-config.php
index 5113dd55b..25f0abd81 100644
--- tests/phpunit/assets/phpunit-wp-config.php
+++ tests/phpunit/assets/phpunit-wp-config.php
@@ -26,10 +26,10 @@ define( 'DB_NAME', 'tests-wordpress');
 define( 'DB_USER', 'root');
 
 /** MySQL database password */
-define( 'DB_PASSWORD', '');
+define( 'DB_PASSWORD', 'password');
 
 /** MySQL hostname */
-define( 'DB_HOST', 'mysql');
+define( 'DB_HOST', 'tests-mysql');
 
 /** Database Charset to use in creating database tables. */
 define( 'DB_CHARSET', 'utf8');
