RIACO Content Protector
RIACO Content Protector

RIACO Content Protector

0/5 (0 ratings) — active installs Updated Jun 12, 2026
Frontend password form

Frontend password form

RIACO Content Protector allows you to protect any part of your WordPress content using a shortcode.
Unlike the built-in post password protection, this plugin protects only what you wrap, not the whole post.

Perfect for:

  • Protecting premium blocks of content
  • Protecting guides, downloads, links, or sensitive sections
  • Paywall-style snippets

Features

  • Protect only specific content inside posts/pages
  • Uses a minimal shortcode:
    [riaco_content_protector] Hidden text here [/riaco_content_protector]
  • Global password stored in plain text, like WordPress page passwords.
  • AJAX-based form — no page reload
  • Unlocks all protected sections on the site after correct password
  • Optional cookie persistence (remember unlocked content for a configurable number of days)
  • Secure implementation using nonces, hashed tokens, and transients
  • Developer-friendly: filters, actions, and JS custom events at every key point in the unlock flow

Important:

  • The global password is stored in plain text, just like WordPress page passwords. It can be read by user with ‘manage_options’ ability.
  • If the global password or “Remember Unlocked” duration is changed in settings, all existing unlock cookies are invalidated. Users will need to re-enter the new password to access protected content.

How It Works

Wrap content you want to protect:

[riaco_content_protector]
This text will be hidden until the visitor enters the password.
[/riaco_content_protector]

Set the global password under:

Settings > Content Protector

Visitors will see a modern, styled form.
After entering the correct password:

  • The content unlocks immediately
  • All other protected areas unlock automatically
  • An optional cookie can keep everything unlocked for a chosen number of days

Security

  • Nonces on every request
  • Secure HMAC token for cookie authentication
  • Sanitized shortcode attributes
  • Escaped output
  • No sensitive data stored in cookies
  • Global password stored in plain text, like WordPress page passwords.

Cookie

The default cookie name is riaco_cp_unlocked_global. The scope suffix global can be changed via the riaco_cp_cookie_scope filter, which also changes the cookie name accordingly.

Style

You can style the content protector box.

It has this class: .riaco-cp--container, so you can add in your style.css:

.riaco-cp--container {
    background: #f8f9fa;
    padding: 20px;
    border: 1px solid #ddd;
    border-radius: 6px;
}

You can replace button classes using:

add_filter( 'riaco_cp_button_classes', function( $classes ) {
    return 'button my-custom-button-class';
});

Or you can remove button classes:

add_filter( 'riaco_cp_button_classes', function( $classes ) {
    return str_replace( 'wp-element-button', '', $classes );
});

For Developers

The plugin exposes actions and filters at every key point so you can extend or customise behaviour without modifying plugin files.

Filters

riaco_cp_default_options — modify the option defaults written on first activation.


add_filter( 'riaco_cp_default_options', function( $defaults ) {
    $defaults['remember_days'] = 30;
    return $defaults;
});


riaco_cp_instance_id — override the computed instance ID for a protected block.


add_filter( 'riaco_cp_instance_id', function( $id, $atts, $content ) {
    return ! empty( $atts['id'] ) ? 'my_prefix_' . $atts['id'] : $id;
}, 10, 3 );


riaco_cp_transient_expiry — change how long protected content is cached (default: `DAY_IN_SECONDS`).


add_filter( 'riaco_cp_transient_expiry', function( $seconds, $instance_id ) {
    return HOUR_IN_SECONDS * 6;
}, 10, 2 );


riaco_cp_lock_message — customise the message shown above the password field.


add_filter( 'riaco_cp_lock_message', function( $message, $instance_id ) {
    return __( 'Members only. Enter your access code:', 'my-theme' );
}, 10, 2 );


riaco_cp_unlocked_content — wrap or replace the HTML around unlocked content.


add_filter( 'riaco_cp_unlocked_content', function( $html, $content, $instance_id ) {
    return '<div class="my-unlocked-wrapper">' . $content . '</div>';
}, 10, 3 );


riaco_cp_cookie_args — modify the options passed to `setcookie()`.


add_filter( 'riaco_cp_cookie_args', function( $args, $cookie_name ) {
    $args['samesite'] = 'Strict';
    return $args;
}, 10, 2 );


riaco_cp_max_attempts — change the brute-force rate-limit threshold (default: 5).


add_filter( 'riaco_cp_max_attempts', function( $max ) {
    return 10;
});


riaco_cp_rate_limit_window — change the rate-limit window in seconds (default: 15 minutes).


add_filter( 'riaco_cp_rate_limit_window', function( $seconds ) {
    return 5 * MINUTE_IN_SECONDS;
});


riaco_cp_content_access — override the cookie check before protected content is rendered. Return `null` to use the default cookie check, `true` to force-grant access, or `false` to force the lock form.


add_filter( 'riaco_cp_content_access', function( $access, $instance_id, $atts ) {
    // Grant access to logged-in users automatically.
    if ( is_user_logged_in() ) {
        return true;
    }
    return null; // Fall through to cookie check for guests.
}, 10, 3 );


riaco_cp_locked_html — replace or wrap the entire locked form HTML.


add_filter( 'riaco_cp_locked_html', function( $html, $instance_id, $atts ) {
    return '<div class="my-paywall">Subscribe to see this content.</div>';
}, 10, 3 );


riaco_cp_validate_password — override password validation. Return `null` to use the default `hash_equals` check, `true` to grant access, or `false` to deny. When non-null, the global password is not consulted.


add_filter( 'riaco_cp_validate_password', function( $result, $user_pass, $instance_id ) {
    // Accept a secondary password for a specific block.
    if ( $instance_id === 'riaco_cp_vip' && $user_pass === 'vip-secret' ) {
        return true;
    }
    return null; // Defer to global password check.
}, 10, 3 );


riaco_cp_rate_limit_bypass — bypass the brute-force counter for trusted IP addresses.


add_filter( 'riaco_cp_rate_limit_bypass', function( $bypass, $ip_address ) {
    $trusted = array( '127.0.0.1', '192.168.1.100' );
    return in_array( $ip_address, $trusted, true );
}, 10, 2 );


riaco_cp_cookie_scope — change the cookie scope suffix (default: `'global'`). The cookie name becomes `riaco_cp_unlocked_{scope}`. Use this to implement per-post or per-instance independent lock states.


add_filter( 'riaco_cp_cookie_scope', function( $scope, $instance_id ) {
    // Use a per-post cookie so each post unlocks independently.
    return 'post_' . get_the_ID();
}, 10, 2 );


riaco_cp_ajax_response — inject additional fields into the JSON success response sent after unlock.


add_filter( 'riaco_cp_ajax_response', function( $data, $instance_id ) {
    $data['redirect'] = home_url( '/members/' );
    return $data;
}, 10, 2 );


riaco_cp_js_data — add extra data to the `RIACO_CP_Ajax` JavaScript object.


add_filter( 'riaco_cp_js_data', function( $data ) {
    $data['my_feature_enabled'] = true;
    return $data;
});

Actions

riaco_cp_loaded — fires after the plugin initialises; receives the `Plugin` instance.


add_action( 'riaco_cp_loaded', function( $plugin ) {
    // $plugin->settings, $plugin->shortcode, etc. are available here.
});


riaco_cp_form_fields — inject extra hidden inputs or markup inside the password form.


add_action( 'riaco_cp_form_fields', function( $instance_id ) {
    echo '<input type="hidden" name="my_field" value="' . esc_attr( $instance_id ) . '">';
});


riaco_cp_password_correct — fires when a visitor enters the correct password.


add_action( 'riaco_cp_password_correct', function( $instance_id ) {
    // Log unlock event, fire analytics, etc.
});


riaco_cp_password_incorrect — fires on a failed attempt; `$attempts` is the running total for this IP.


add_action( 'riaco_cp_password_incorrect', function( $instance_id, $attempts ) {
    if ( $attempts >= 3 ) {
        // Send alert, block IP in your firewall, etc.
    }
}, 10, 2 );


riaco_cp_cookie_set — fires after the unlock cookie is written.


add_action( 'riaco_cp_cookie_set', function( $cookie_name, $expire ) {
    // Record unlock timestamp, sync to a log, etc.
}, 10, 2 );


riaco_cp_settings_page_after — fires after the free plugin's settings form. Use it to render your own `<form>` block with additional settings fields below the existing form.


add_action( 'riaco_cp_settings_page_after', function() {
    // Render a separate settings form here.
});

JavaScript Custom Events

The plugin triggers jQuery custom events on the .riaco-cp--container element at key moments. Listen from any JavaScript file that loads after the plugin’s script.

riaco_cp:before_submit — fires just before the AJAX password call. Call `e.preventDefault()` to cancel the submission (the UI is restored automatically).


$(document).on('riaco_cp:before_submit', '.riaco-cp--container', function(e, instanceId, password) {
    // e.preventDefault(); // uncomment to cancel submission
});


riaco_cp:unlock_success — fires after a successful AJAX response, before the container is replaced with unlocked content.


$(document).on('riaco_cp:unlock_success', '.riaco-cp--container', function(e, instanceId, responseData) {
    console.log('Unlocked:', instanceId, responseData);
});


riaco_cp:unlock_error — fires on wrong password, rate-limit hit, or network/server failure.


$(document).on('riaco_cp:unlock_error', '.riaco-cp--container', function(e, instanceId, errorMessage) {
    console.warn('Unlock failed for', instanceId, errorMessage);
});

License

This plugin is licensed under GPLv2 or later.