';
printf(
/* translators: %s: WordPress version number */
esc_html__('Absoluto Access Gate requires WordPress 5.0 or higher. You are running WordPress %s. Please upgrade WordPress to activate this plugin.', 'absoluto-access-gate'),
esc_html(get_bloginfo('version'))
);
echo '
';
});
return;
}
// Check PHP version
if (version_compare(PHP_VERSION, '7.0', '<')) {
add_action('admin_notices', function() {
echo '
';
printf(
/* translators: %s: PHP version number */
esc_html__('Absoluto Access Gate requires PHP 7.0 or higher. You are running PHP %s. Please upgrade PHP to activate this plugin.', 'absoluto-access-gate'),
esc_html(PHP_VERSION)
);
echo '
';
});
return;
}
// Define plugin constants
define('ABSACGA_VERSION', '1.0.0');
define('ABSACGA_PLUGIN_DIR', plugin_dir_path(__FILE__));
define('ABSACGA_PLUGIN_URL', plugin_dir_url(__FILE__));
define('ABSACGA_MIN_WP_VERSION', '5.0');
define('ABSACGA_MIN_PHP_VERSION', '7.0');
class Absoluto_Access_Gate {
/**
* Instance of this class
*/
private static $instance = null;
/**
* Get instance of this class
*/
public static function get_instance() {
if (null === self::$instance) {
self::$instance = new self();
}
return self::$instance;
}
/**
* Constructor
*/
private function __construct() {
// Hook into WordPress
add_action('template_redirect', array($this, 'force_login_redirect'));
add_action('admin_menu', array($this, 'add_admin_menu'));
add_action('admin_init', array($this, 'register_settings'));
add_action('admin_enqueue_scripts', array($this, 'enqueue_admin_scripts'));
add_action('login_message', array($this, 'display_login_message'));
add_action('admin_bar_menu', array($this, 'add_admin_bar_notice'), 999);
// Add settings link to plugin actions
$plugin_file = plugin_basename(__FILE__);
add_filter("plugin_action_links_{$plugin_file}", array($this, 'add_plugin_action_links'));
}
/**
* Force login redirect
*/
public function force_login_redirect() {
// Check if plugin is enabled
$plugin_enabled = get_option('absacga_enabled', '1');
if ($plugin_enabled !== '1') {
return;
}
// Don't redirect if user is logged in and has bypass permission
if (is_user_logged_in() && $this->can_bypass_login()) {
return;
}
// Don't redirect if current page is excluded
if ($this->is_page_excluded()) {
return;
}
// Don't redirect if post type is excluded
if ($this->is_post_type_excluded()) {
return;
}
// Don't redirect if category/tag is excluded
if ($this->is_taxonomy_excluded()) {
return;
}
// Don't redirect RSS feeds if excluded
if ($this->is_rss_excluded() && (is_feed() || is_comment_feed())) {
return;
}
// Don't redirect REST API if excluded
if ($this->is_rest_api_excluded() && $this->is_rest_api_request()) {
return;
}
// Check bypass key/token
if ($this->has_bypass_key()) {
return;
}
// Check IP whitelist
if ($this->is_ip_whitelisted()) {
return;
}
// Check if maintenance mode is enabled
if ($this->is_maintenance_mode()) {
$this->show_maintenance_page();
return;
}
// Don't redirect AJAX requests if option is enabled
if ($this->exclude_ajax() && wp_doing_ajax()) {
return;
}
// Don't redirect archive/search pages if excluded
if ($this->is_archive_excluded() && (is_archive() || is_search() || is_404())) {
return;
}
// Don't redirect if already on login page
if (is_admin() || $this->is_login_page()) {
return;
}
// Redirect to login page
if (!is_user_logged_in()) {
// Sanitize current URL
$protocol = is_ssl() ? 'https://' : 'http://';
$host = isset($_SERVER['HTTP_HOST']) ? sanitize_text_field(wp_unslash($_SERVER['HTTP_HOST'])) : '';
$request_uri = isset($_SERVER['REQUEST_URI']) ? esc_url_raw(wp_unslash($_SERVER['REQUEST_URI'])) : '';
$current_url = $protocol . $host . $request_uri;
$redirect_back = get_option('absacga_redirect_back', '1');
$custom_redirect = get_option('absacga_custom_redirect_url', '');
// Get custom login page URL
$custom_login_url = get_option('absacga_custom_login_url', '');
if (!empty($custom_login_url)) {
// Validate custom login URL
$custom_login_url = esc_url_raw($custom_login_url);
// Use custom login URL
if ($redirect_back === '1') {
$redirect_url = add_query_arg('redirect_to', rawurlencode($current_url), $custom_login_url);
} elseif (!empty($custom_redirect)) {
$redirect_url = add_query_arg('redirect_to', rawurlencode(esc_url_raw($custom_redirect)), $custom_login_url);
} else {
$redirect_url = add_query_arg('redirect_to', rawurlencode(home_url()), $custom_login_url);
}
} else {
// Use default WordPress login
if ($redirect_back === '1') {
$redirect_url = wp_login_url($current_url);
} elseif (!empty($custom_redirect)) {
$redirect_url = wp_login_url(esc_url_raw($custom_redirect));
} else {
$redirect_url = wp_login_url(home_url());
}
}
// Allow filtering of redirect URL
$redirect_url = apply_filters('absacga_login_redirect_url', $redirect_url, $current_url);
// Sanitize final redirect URL
$redirect_url = esc_url_raw($redirect_url);
wp_safe_redirect($redirect_url);
exit;
}
}
/**
* Check if user can bypass login requirement
*/
private function can_bypass_login() {
$bypass_roles = get_option('absacga_bypass_roles', array());
$bypass_users = get_option('absacga_bypass_users', array());
// Check user roles
if (!empty($bypass_roles)) {
$user = wp_get_current_user();
if (!empty($user->roles)) {
foreach ($user->roles as $role) {
if (in_array($role, $bypass_roles)) {
return true;
}
}
}
}
// Check specific users
if (!empty($bypass_users)) {
$current_user_id = get_current_user_id();
if (in_array($current_user_id, array_map('intval', $bypass_users))) {
return true;
}
}
return false;
}
/**
* Check if current page is excluded
*/
private function is_page_excluded() {
$excluded_pages = get_option('absacga_excluded_pages', array());
if (empty($excluded_pages)) {
return false;
}
// Check if current page/post ID is excluded
if (is_singular()) {
$current_id = get_queried_object_id();
if (in_array($current_id, array_map('intval', $excluded_pages))) {
return true;
}
}
// Check if current page template is excluded
$excluded_templates = get_option('absacga_excluded_templates', array());
if (!empty($excluded_templates) && is_page()) {
$template = get_page_template_slug();
if (!empty($template) && in_array($template, $excluded_templates)) {
return true;
}
}
return false;
}
/**
* Check if current page is login page
*/
private function is_login_page() {
return in_array($GLOBALS['pagenow'], array('wp-login.php', 'wp-register.php'));
}
/**
* Check if current post type is excluded
*/
private function is_post_type_excluded() {
$excluded_post_types = get_option('absacga_excluded_post_types', array());
if (empty($excluded_post_types)) {
return false;
}
if (is_singular()) {
$post_type = get_post_type();
if (in_array($post_type, $excluded_post_types)) {
return true;
}
}
if (is_post_type_archive()) {
$post_type = get_post_type();
if (in_array($post_type, $excluded_post_types)) {
return true;
}
}
return false;
}
/**
* Check if current taxonomy term is excluded
*/
private function is_taxonomy_excluded() {
$excluded_categories = get_option('absacga_excluded_categories', array());
$excluded_tags = get_option('absacga_excluded_tags', array());
if (empty($excluded_categories) && empty($excluded_tags)) {
return false;
}
if (is_category()) {
$category_id = get_queried_object_id();
if (in_array($category_id, array_map('intval', $excluded_categories))) {
return true;
}
}
if (is_tag()) {
$tag_id = get_queried_object_id();
if (in_array($tag_id, array_map('intval', $excluded_tags))) {
return true;
}
}
if (is_singular()) {
// Check if post belongs to excluded category
$categories = wp_get_post_categories(get_the_ID());
if (!empty($categories) && !empty($excluded_categories)) {
foreach ($categories as $cat_id) {
if (in_array($cat_id, array_map('intval', $excluded_categories))) {
return true;
}
}
}
// Check if post has excluded tag
$tags = wp_get_post_tags(get_the_ID(), array('fields' => 'ids'));
if (!empty($tags) && !empty($excluded_tags)) {
foreach ($tags as $tag_id) {
if (in_array($tag_id, array_map('intval', $excluded_tags))) {
return true;
}
}
}
}
return false;
}
/**
* Check if RSS feeds are excluded
*/
private function is_rss_excluded() {
return get_option('absacga_exclude_rss', '0') === '1';
}
/**
* Check if REST API is excluded
*/
private function is_rest_api_excluded() {
return get_option('absacga_exclude_rest_api', '0') === '1';
}
/**
* Check if current request is REST API
*/
private function is_rest_api_request() {
if (defined('REST_REQUEST') && REST_REQUEST) {
return true;
}
if (!isset($_SERVER['REQUEST_URI'])) {
return false;
}
$rest_prefix = trailingslashit(rest_get_url_prefix());
$request_uri = sanitize_text_field(wp_unslash($_SERVER['REQUEST_URI']));
return strpos($request_uri, $rest_prefix) !== false;
}
/**
* Check if bypass key is present in URL
*/
private function has_bypass_key() {
$bypass_key = get_option('absacga_bypass_key', '');
if (empty($bypass_key)) {
return false;
}
// Validate bypass key from URL parameter (public-facing, no nonce needed)
// phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Public URL parameter, not form data
if (!isset($_GET['absacga_bypass'])) {
return false;
}
// phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Public URL parameter, not form data
$key_param = sanitize_text_field(wp_unslash($_GET['absacga_bypass']));
// Use hash_equals for timing-safe comparison
return hash_equals($bypass_key, $key_param);
}
/**
* Check if current IP is whitelisted
*/
private function is_ip_whitelisted() {
$whitelisted_ips = get_option('absacga_whitelist_ips', '');
if (empty($whitelisted_ips)) {
return false;
}
$current_ip = $this->get_client_ip();
$ips = array_map('trim', explode("\n", $whitelisted_ips));
foreach ($ips as $ip) {
if (empty($ip)) {
continue;
}
// Support CIDR notation
if (strpos($ip, '/') !== false) {
if ($this->ip_in_range($current_ip, $ip)) {
return true;
}
} else {
if ($current_ip === $ip) {
return true;
}
}
}
return false;
}
/**
* Get client IP address
*/
private function get_client_ip() {
$ip_keys = array('HTTP_CLIENT_IP', 'HTTP_X_FORWARDED_FOR', 'HTTP_X_FORWARDED', 'HTTP_X_CLUSTER_CLIENT_IP', 'HTTP_FORWARDED_FOR', 'HTTP_FORWARDED', 'REMOTE_ADDR');
foreach ($ip_keys as $key) {
if (isset($_SERVER[$key]) && !empty($_SERVER[$key])) {
$ip_value = sanitize_text_field(wp_unslash($_SERVER[$key]));
foreach (explode(',', $ip_value) as $ip) {
$ip = trim($ip);
// Validate IP address
if (filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE) !== false) {
return $ip;
}
}
}
}
// Fallback to REMOTE_ADDR
if (isset($_SERVER['REMOTE_ADDR'])) {
$remote_addr = sanitize_text_field(wp_unslash($_SERVER['REMOTE_ADDR']));
if (filter_var($remote_addr, FILTER_VALIDATE_IP) !== false) {
return $remote_addr;
}
}
return '0.0.0.0';
}
/**
* Check if IP is in CIDR range
*/
private function ip_in_range($ip, $range) {
if (strpos($range, '/') === false) {
return $ip === $range;
}
list($subnet, $mask) = explode('/', $range);
$ip_long = ip2long($ip);
$subnet_long = ip2long($subnet);
$mask_long = -1 << (32 - (int)$mask);
return ($ip_long & $mask_long) === ($subnet_long & $mask_long);
}
/**
* Check if maintenance mode is enabled
*/
private function is_maintenance_mode() {
return get_option('absacga_maintenance_mode', '0') === '1';
}
/**
* Show maintenance page
*/
private function show_maintenance_page() {
$maintenance_message = get_option('absacga_maintenance_message', __('We are currently performing scheduled maintenance. Please check back soon.', 'absoluto-access-gate'));
$maintenance_title = get_option('absacga_maintenance_title', __('Site Under Maintenance', 'absoluto-access-gate'));
status_header(503);
nocache_headers();
?>
>