WordPress Security

WordPress Security for Membership Sites: Protecting Content and Subscribers

Secure your WordPress membership site with strategies to protect premium content, subscriber data, and recurring payment information.

S
Sarah Chen
9 min read
2,084 views
Security guide for WordPress membership websites

Membership sites must protect premium content from unauthorized access while securing subscriber data and payment information. Implementing robust security measures is essential for maintaining member trust and revenue.

Membership Site Security Challenges

Membership platforms face specific threats:

  • Content scraping and redistribution
  • Account credential sharing
  • Payment fraud and chargebacks
  • Subscription manipulation
  • Member data breaches

Content Protection Levels

Implement tiered content access:

function check_content_access($post_id) {
    $access_level = get_post_meta($post_id, '_membership_level', true);

    if (empty($access_level) || $access_level === 'public') {
        return true; // Public content
    }

    if (!is_user_logged_in()) {
        return false;
    }

    $user_level = get_user_membership_level(get_current_user_id());

    $level_hierarchy = array(
        'free' => 1,
        'basic' => 2,
        'premium' => 3,
        'vip' => 4,
    );

    $required = $level_hierarchy[$access_level] ?? 0;
    $user_has = $level_hierarchy[$user_level] ?? 0;

    return $user_has >= $required;
}

add_filter('the_content', function($content) {
    if (!is_singular()) {
        return $content;
    }

    if (!check_content_access(get_the_ID())) {
        return get_membership_teaser(get_the_ID());
    }

    return $content;
});

Subscription Validation

Verify active subscriptions before granting access:

function has_active_subscription($user_id) {
    $subscription = get_user_subscription($user_id);

    if (!$subscription) {
        return false;
    }

    // Check expiration
    if ($subscription['expires_at'] && strtotime($subscription['expires_at']) < time()) {
        return false;
    }

    // Check status
    if (!in_array($subscription['status'], array('active', 'trialing'))) {
        return false;
    }

    // Check payment status
    if ($subscription['payment_failed']) {
        $grace_period = get_option('membership_grace_period', 7);
        $failed_at = strtotime($subscription['payment_failed_at']);

        if ((time() - $failed_at) > ($grace_period * 86400)) {
            return false;
        }
    }

    return true;
}

// Cache subscription check for performance
function get_user_membership_status($user_id) {
    $cache_key = 'membership_status_' . $user_id;
    $status = wp_cache_get($cache_key);

    if ($status === false) {
        $status = has_active_subscription($user_id);
        wp_cache_set($cache_key, $status, '', 300); // 5 minute cache
    }

    return $status;
}

Preventing Account Sharing

Detect and limit credential sharing:

function enforce_session_limits($user_id) {
    $max_sessions = get_membership_session_limit($user_id);
    $sessions = WP_Session_Tokens::get_instance($user_id);
    $all_sessions = $sessions->get_all();

    if (count($all_sessions) > $max_sessions) {
        // Keep newest sessions, destroy oldest
        uasort($all_sessions, function($a, $b) {
            return $b['login'] - $a['login'];
        });

        $to_keep = array_slice($all_sessions, 0, $max_sessions, true);
        $to_destroy = array_diff_key($all_sessions, $to_keep);

        foreach (array_keys($to_destroy) as $token) {
            $sessions->destroy($token);
        }
    }
}

// Track login patterns
function analyze_login_patterns($user_id) {
    global $wpdb;

    $logins = $wpdb->get_results($wpdb->prepare(
        "SELECT ip_address, COUNT(*) as count,
                COUNT(DISTINCT ip_address) as unique_ips
         FROM membership_logins
         WHERE user_id = %d
         AND login_at > DATE_SUB(NOW(), INTERVAL 7 DAY)
         GROUP BY ip_address",
        $user_id
    ));

    $unique_ips = count($logins);
    $threshold = get_option('suspicious_ip_threshold', 5);

    if ($unique_ips > $threshold) {
        flag_account_for_review($user_id, 'Excessive unique IPs: ' . $unique_ips);
    }
}

Content Scraping Prevention

Detect and block content scrapers:

function detect_scraping_behavior() {
    $ip = $_SERVER['REMOTE_ADDR'];
    $user_agent = $_SERVER['HTTP_USER_AGENT'] ?? '';

    // Rate limit content views
    $view_key = 'content_views_' . md5($ip);
    $views = get_transient($view_key) ?: 0;

    if ($views > 50) { // 50 pages per 5 minutes
        log_scraping_attempt($ip, $user_agent);
        wp_die('Access temporarily restricted');
    }

    set_transient($view_key, $views + 1, 300);

    // Check for missing JavaScript execution
    if (isset($_COOKIE['js_check']) && $_COOKIE['js_check'] !== get_expected_js_token()) {
        log_scraping_attempt($ip, 'JS verification failed');
    }

    // Check for known scraper user agents
    $scrapers = array('HTTrack', 'wget', 'curl', 'python-requests', 'scrapy');

    foreach ($scrapers as $scraper) {
        if (stripos($user_agent, $scraper) !== false) {
            wp_die('Automated access not permitted');
        }
    }
}
add_action('template_redirect', 'detect_scraping_behavior');

Secure Member Registration

Validate and verify new member signups:

function process_member_registration($data) {
    // Validate email
    if (!is_email($data['email'])) {
        return new WP_Error('invalid_email', 'Please enter a valid email');
    }

    // Check for disposable email
    $email_domain = substr(strrchr($data['email'], '@'), 1);
    if (is_disposable_email_domain($email_domain)) {
        return new WP_Error('disposable_email', 'Disposable emails not allowed');
    }

    // Check for existing account
    if (email_exists($data['email'])) {
        // Do not reveal account existence
        return new WP_Error('registration_error', 'Registration failed. Please try again.');
    }

    // Rate limit registrations
    $ip = $_SERVER['REMOTE_ADDR'];
    $reg_key = 'registrations_' . md5($ip);
    $recent = get_transient($reg_key) ?: 0;

    if ($recent > 3) { // 3 registrations per hour
        return new WP_Error('rate_limit', 'Too many registration attempts');
    }

    set_transient($reg_key, $recent + 1, HOUR_IN_SECONDS);

    // Create user
    $user_id = wp_create_user(
        sanitize_user($data['username']),
        wp_generate_password(16, true),
        sanitize_email($data['email'])
    );

    if (is_wp_error($user_id)) {
        return $user_id;
    }

    // Send verification email
    send_email_verification($user_id);

    return array('user_id' => $user_id, 'status' => 'pending_verification');
}

Payment Security

Secure subscription payment handling:

function process_subscription_payment($user_id, $payment_data) {
    // Verify nonce
    if (!wp_verify_nonce($payment_data['nonce'], 'membership_payment')) {
        return new WP_Error('invalid_nonce', 'Security check failed');
    }

    // Validate plan
    $plan = get_membership_plan($payment_data['plan_id']);

    if (!$plan || !$plan['active']) {
        return new WP_Error('invalid_plan', 'Selected plan not available');
    }

    // Log payment attempt
    log_payment_attempt($user_id, $plan['id'], $_SERVER['REMOTE_ADDR']);

    // Process through Stripe (example)
    try {
        $subscription = create_stripe_subscription(
            get_user_stripe_customer_id($user_id),
            $plan['stripe_price_id']
        );

        // Store subscription locally
        save_user_subscription($user_id, array(
            'stripe_subscription_id' => $subscription->id,
            'plan_id' => $plan['id'],
            'status' => $subscription->status,
            'current_period_end' => date('Y-m-d H:i:s', $subscription->current_period_end),
        ));

        return array('success' => true, 'subscription_id' => $subscription->id);

    } catch (Exception $e) {
        log_payment_error($user_id, $e->getMessage());
        return new WP_Error('payment_failed', 'Payment could not be processed');
    }
}

Member Data Protection

Secure member personal information:

function export_member_data($user_id) {
    // Verify request is from the user
    if (get_current_user_id() !== $user_id && !current_user_can('manage_options')) {
        return new WP_Error('unauthorized', 'Cannot export other member data');
    }

    $user = get_userdata($user_id);

    $data = array(
        'profile' => array(
            'username' => $user->user_login,
            'email' => $user->user_email,
            'registered' => $user->user_registered,
        ),
        'membership' => get_user_subscription($user_id),
        'content_history' => get_user_content_history($user_id),
        'payment_history' => get_masked_payment_history($user_id),
    );

    // Log data export
    log_data_export($user_id, get_current_user_id());

    return $data;
}

function delete_member_account($user_id) {
    // Cancel any active subscriptions
    cancel_user_subscriptions($user_id);

    // Anonymize payment records
    anonymize_payment_records($user_id);

    // Delete personal data
    delete_user_content_history($user_id);

    // Delete WordPress user
    require_once ABSPATH . 'wp-admin/includes/user.php';
    wp_delete_user($user_id);

    // Log deletion
    log_account_deletion($user_id);
}

Conclusion

Membership site security requires tiered content protection, subscription validation, account sharing prevention, and robust payment security. Regular monitoring helps identify and address potential security issues before they impact members.

Share:
S
Written by Sarah Chen

WP Folder Shield Team

Related Articles

SEO Spam Injection: How to Detect Hidden Links and Malicious Redirects
SEO Spam Injection: How to Detect Hidden Links and Malicious Redirects

Learn how hackers inject hidden links and malicious redirects into WordPress sites to steal your...

January 18, 2026
Understanding WordPress Malware Signatures and Detection Patterns
Understanding WordPress Malware Signatures and Detection Patterns

Learn how malware scanners detect threats using signatures and patterns. Understand the technology...

January 15, 2026
Country Blocking for WooCommerce: Protect Your Online Store
Country Blocking for WooCommerce: Protect Your Online Store

Learn how to implement country blocking for WooCommerce stores. Prevent fraud, reduce chargebacks...

January 10, 2026

Ready to Secure Your WordPress Site?

Get complete protection with WP Folder Shield.

Get Started