Introduction
Traffic Cop is a security-focused WordPress plugin primarily designed for developers and site operators. On this page you will mainly find the technical documentation of the plugin.
Obtaining a License and Configuration
You must obtain the license and complete the configuration before installation.
- Register in the Shop
- Click the confirmation link in the email you receive
- Log in to the Shop
- Create a billing profile in the Shop
- Purchase the product in the Shop
- Pay by credit card or bank transfer
- Select the license in the Shop
- Activate the license by entering the WordPress Address (URL, not the Site Address) in the Shop
- Download the plugin from the Shop
- Upload and activate the plugin in WordPress
- Copy the license key from the Shop
- Configure the license key in WordPress
Purchasing a License
The plugin is sold under a license. You can purchase it via the Cone Shop: https://shop.conedevelopment.com/traffic-cop. After registering, logging in, and providing your billing details, you can purchase licenses for as many sites as you need.
After the purchase, the system automatically generates a license key. First, you must activate your store URL for this key, and then, after installing the plugin, you must enter the license key in WordPress.
Activating the URL / Domain
You can access previously purchased licenses at https://shop.conedevelopment.com/account/licenses.
Within each license, you can associate your store’s URL with the license key, ensuring that later activation will succeed.
Installation
You can perform the installation after obtaining the license and completing the configuration.
Via the WordPress Plugin Manager
On the license settings page, select the desired version and download the plugin, which you can then install on your WordPress instance.
After downloading, locate the .zip file and upload it to the target WordPress instance.
- Navigate to Plugins → Add New.
- Click the Upload Plugin button at the top.
- In the new section that appears, click to choose a file, then select the
.zipfile you downloaded earlier. - Click the Install Now button.
After the upload, you will see a screen confirming that the plugin has been successfully installed. This is a simple page where you can follow the steps of the installation process.
As you can see on this screen, you can activate the plugin immediately. Click the Activate Plugin button and your Traffic Cop plugin will start running.
If you skip activation on this page, you can always activate (enable/disable), delete, or update the plugin later under Plugins / Installed Plugins.
You can find the plugin settings under Plugins / Installed Plugins / Traffic Cop by clicking the Settings link.
Here you can assign the license key to the plugin. This is an important step, because without validation the plugin will not work, and updates cannot be downloaded via the WordPress system.
Via the Composer Package Manager
Composer is a widely used dependency manager for PHP applications. In some setups, you may want to manage your WordPress installation and its dependencies with Composer.
The example composer.json below shows how to configure the conedevelopment/traffic-cop package so that Composer can download it from the correct location.
{
"name": "conedevelopment/example-wp-composer",
"description": "Example WordPress with Composer",
"license": "MIT",
"require": {
"php": "^8.3.0",
"conedevelopment/traffic-cop": "^1.3.3",
"roots/wordpress": "^6.6.0"
},
"minimum-stability": "beta",
"config": {
"preferred-install": {
"*": "dist"
},
"allow-plugins": {
"composer/installers": true,
"ffraenz/private-composer-installer": true,
"roots/wordpress-core-installer": true
}
},
"extra": {
"installer-paths": {
"wp-content/mu-plugins/{$name}/": [
"type:wordpress-muplugin"
],
"wp-content/plugins/{$name}/": [
"type:wordpress-plugin"
],
"wp-content/themes/{$name}/": [
"type:wordpress-theme"
]
}
},
"repositories": [
{
"type": "composer",
"url": "https://wpackagist.org"
},
{
"type": "package",
"package": {
"name": "conedevelopment/traffic-cop",
"version": "1.3.3",
"type": "wordpress-plugin",
"dist": {
"type": "zip",
"url": "https://shop.conedevelopment.com/api/packages/{%CONE_LICENSE_KEY}/download?version=v{%VERSION}"
},
"require": {
"composer/installers": "^2.3.0",
"ffraenz/private-composer-installer": "^5.0"
}
}
}
]
}
The {%VERSION} placeholder resolves to the value of the version key, 1.3.3 in this case.
However, it is not recommended to store {%CONE_LICENSE_KEY} directly in composer.json (especially if this file is tracked in Git). Instead, you should place it in an environment variable. This can be a .env variable or an environment variable defined in your CI (GitHub Actions, GitLab CI, etc.):
# Not a real license key!
CONE_LICENSE_KEY=eb819bed-ba18-4e60-9d95-d6d6b5d4364c
WAF
A WAF (Web Application Firewall) function is to filter HTTP requests based on certain rules, and block those requests that fail the filter, before they cause a load on the server.
Ideally, this function is not implemented within WordPress itself, but in shared hosting environments it is often the case that WAF is not available, so an alternative solution is needed. The plugin provides this alternative.
The operation is very simple: incoming HTTP requests are analyzed based on the specified rules, and if any of the criteria are not met by the request, a 403 (Forbidden) HTTP response is returned by the plugin, thus minimizing load and security risks on the server.
The rules are layered, so multiple rules can be applied to a request. For example, a request is first checked against the IP rule, and if it passes the criteria, then the URI rule is checked and so on.
The rules can be enabled or disabled individually, allowing you to customize the level of protection. To do this, you can use the traffic-cop/waf/rule_enabled filter.
Default WAF Rules
- IP rule: a ~10 year old, continuously refreshed IP address list is used, which contains IP addresses that send malicious HTTP requests. The rule is to block the request if the IP address appears in one of the blocked ranges.
- URI rule: a predefined URI "blacklist" is used, which typically contains sensitive URIs. The rule is to block the request if the URI appears in the list.
- User Agent rule: a predefined User Agent rule is used. The rule is to block the request if the User Agent appears in the list.
- HTTP Protocol rule: it checks the HTTP protocol of the request. The rule is to block the request if it does not meet the criteria defined in the rule.
- Query String rule: it checks the query string of the HTTP request. The rule is to block the request if it does not meet the criteria defined in the rule.
- Redirect rule: a HTTP request redirect behavior is examined. The rule is to block the request if it contains a redirect URL that does not meet the criteria defined in the rule.
- User Enumeration rule: it checks for attempts to enumerate users via the
authorquery parameter. The rule is to block the request if it contains such an attempt. - File Upload rule: it checks for suspicious file upload attempts. The rule is to block the request if it contains such an attempt.
Creating Custom WAF Rules
The plugin provides the ability to create and apply custom WAF rules in addition to the existing rules. For example, we can create a rule that blocks OPTIONS HTTP method requests:
use Cone\TrafficCop\Waf\Rule;
class MethodRule extends Rule
{
/**
* The HTTP method.
*/
protected string $method;
/**
* Create a new HTTP method rule instance.
*/
public function __construct(string $method)
{
$this->method = $method;
}
/**
* Create a new HTTP method rule instance from raw data.
*/
public static function fromRaw(): static
{
return new static(strtoupper($_SERVER['REQUEST_METHOD'] ?? ''));
}
/**
* Get the source of the rule.
*/
public function source(): string
{
return $this->method;
}
/**
* Check whether the rule applies.
*/
public function check(): bool
{
if ($this->method === 'OPTIONS') {
return false;
}
return true;
}
}
Custom rules can be applied by using the traffic-cop/waf/rules filter:
add_filter('traffic-cop/waf/rules', function (array $rules): array {
$rules[] = MethodRule::class;
return $rules;
});
Settings
You can find the WAF settings under Settings → Traffic Cop → WAF.
Rate Limiter
The Rate Limiter feature is intended to limit certain HTTP requests (e.g. bot requests) within a given time window (e.g. 10 seconds), for example to 3 requests within that window.
This is necessary because content-scanning bots (e.g. Google bot, Facebook bot) can generate significant load on the server in a very short time. This slows down the site and every related process, degrades the user experience, and can sometimes make the interface temporarily unusable.
Important: If we want to allow bots (e.g. for advertising purposes), we must configure this properly. Currently, most bots can send 1 request per 10 seconds.
Currently, you can choose from three Rate Limiter drivers: Transient, Redis, and Shmop.
Environment configuration using .htaccess
If we want, we can pass values corresponding to the desired rules to the Rate Limiter using .htaccess. For example:
RewriteCond %{HTTP_USER_AGENT} "^Mozilla.*(Chrome|Firefox|Safari)"
RewriteCond %{HTTP_ACCEPT_LANGUAGE} "^$"
RewriteCond %{HTTP_ACCEPT_ENCODING} "^gzip$"
RewriteCond %{HTTP_CONNECTION} "^keep-alive$"
RewriteCond %{HTTP_REFERER} "."
RewriteRule ^ - [E=RATE_LIMIT_KEY:Chinese-attacker,E=RATE_LIMIT_INTERVAL:10,E=RATE_LIMIT_LIMIT:1]
Important, the RATE_LIMIT_KEY, RATE_LIMIT_INTERVAL and RATE_LIMIT_LIMIT env variables must be specified in all cases.
Transient Driver
Transients are part of the WordPress core API. This option can be used without any prior setup or configuration.
Redis Driver
Redis is an open-source, in-memory, NoSQL key-value store that provides fast data processing. Because of its flexibility and speed, it is recommended when your site handles a higher volume of traffic.
Using this driver requires the redis PHP extension and the appropriate configuration in the wp-config.php file:
// e.g.:
define('TRAFFIC_COP_REDIS_CONFIG', [
'host' => '127.0.0.1',
'port' => 6379,
'auth' => 'password',
'database' => 0,
]);
Shmop Driver
The "shmop" (shared memory operation) extension is a PHP module that allows simple handling of shared memory segments on Unix-based systems. It provides functions in PHP for reading, writing, creating, and deleting shared memory segments.
Using this driver requires the shmop extension to be installed.
Settings
You can find the Rate Limiter settings under Settings → Traffic Cop → Rate Limiter.
Hook Index
The plugin allows you to influence its behavior through filters. By using these hooks correctly, you can implement highly customized solutions.
traffic-cop/waf/rules (Filter)
If we want to add a custom WAF rule to the existing rules, we can do this with the traffic-cop/waf/rules filter:
add_filter('traffic-cop/waf/rules', function (array $rules): array {
$rules[] = CustomRule::class;
return $rules;
});
traffic-cop/waf/rule_enabled (Filter)
If we want to enable or disable a specific WAF rule based on unique logic, we can do this with the traffic-cop/waf/rule_enabled filter:
add_filter('traffic-cop/waf/rule_enabled', function (bool $enabled, Cone\TrafficCop\Waf\Rule $rule): bool {
return match ($rule) {
$rule instanceof Cone\WordPress\TrafficCop\Waf\FileUploadRule => true,
$rule instanceof Cone\WordPress\TrafficCop\Waf\IpRule => true,
$rule instanceof Cone\WordPress\TrafficCop\Waf\ProtocolRule => true,
$rule instanceof Cone\WordPress\TrafficCop\Waf\QueryStringRule => true,
$rule instanceof Cone\WordPress\TrafficCop\Waf\RedirectRule => true,
$rule instanceof Cone\WordPress\TrafficCop\Waf\UriRule => true,
$rule instanceof Cone\WordPress\TrafficCop\Waf\UserAgentRule => true,
$rule instanceof Cone\WordPress\TrafficCop\Waf\UserEnumerationRule => true,
default => $enabled,
};
});
traffic-cop/waf/blocked (Action)
If we want to take action when the WAF blocked a HTTP request, we can do this with the traffic-cop/waf/blocked action:
add_action('traffic-cop/waf/blocked', function (Cone\TrafficCop\Waf\Rule $rule): void {
match ($rule) {
$rule instanceof Cone\WordPress\TrafficCop\Waf\FileUploadRule => handleValue($rule->source()),
$rule instanceof Cone\WordPress\TrafficCop\Waf\IpRule => handleValue($rule->source()),
$rule instanceof Cone\WordPress\TrafficCop\Waf\ProtocolRule => handleValue($rule->source()),
$rule instanceof Cone\WordPress\TrafficCop\Waf\QueryStringRule => handleValue($rule->source()),
$rule instanceof Cone\WordPress\TrafficCop\Waf\RedirectRule => handleValue($rule->source()),
$rule instanceof Cone\WordPress\TrafficCop\Waf\UriRule => handleValue($rule->source()),
$rule instanceof Cone\WordPress\TrafficCop\Waf\UserAgentRule => handleValue($rule->source()),
$rule instanceof Cone\WordPress\TrafficCop\Waf\UserEnumerationRule => handleValue($rule->source()),
default => null,
};
});
traffic-cop/waf/ip_bypass (Filter)
If you want to explicitly allow or, conversely, block a specific IP address—regardless of whether it is present in the IP list—you can do so with the traffic-cop/waf/ip_bypass filter:
add_filter('traffic-cop/waf/ip_bypass', function (?bool $pass, string $ip): ?bool {
return match (true) {
in_array($ip, $enabled) => true,
in_array($ip, $blocked) => false,
default => $pass,
};
}, 10, 2);
traffic-cop/rate_limiter/key (Filter)
If you want to modify the Rate Limiter key (that is, the value used to distinguish between individual HTTP requests), you can do so with the traffic-cop/rate_limiter/key filter:
add_filter('traffic-cop/rate_limiter/key', function (string $key): string {
return $_SERVER['REMOTE_ADDR'];
});
traffic-cop/rate_limiter/limit (Filter)
If you want to modify the limit applied to a given key within the configured interval, you can do so with the traffic-cop/rate_limiter/limit filter:
add_filter('traffic-cop/rate_limiter/limit', function (int $limit): int {
return match (true) {
isBot() => 1,
default => $limit,
};
});
traffic-cop/rate_limiter/interval (Filter)
If you want to modify the time interval itself, you can do so with the traffic-cop/rate_limiter/interval filter:
add_filter('traffic-cop/rate_limiter/interval', function (int $interval): int {
return match (true) {
isBot() => 10,
default => $interval,
};
});
traffic-cop/rate_limiter/limited (Filter)
If you want to control, using custom logic, for which requests the rate limit should apply, you can do so with the traffic-cop/rate_limiter/limited filter:
add_filter('traffic-cop/rate_limiter/limited', function (bool $limited): bool {
return match (true) {
isBot() => true,
default => false,
};
});
traffic-cop/rate_limiter/hit (Action)
If we want to perform an action when the Rate Limiter has run out, we can do this with the traffic-cop/rate_limiter/hit action:
add_action('traffic-cop/rate_limiter/hit', function (string $ip): void {
//
});
traffic-cop/rate_limiter/blocked (Action)
If we want to perform an action if the Rate Limiter has reached the limit and blocked the request, we can do this with the traffic-cop/rate_limiter/blocked action:
add_action('traffic-cop/rate_limiter/blocked', function (string $ip): void {
//
});