About this plugin
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.
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.
</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.
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
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. preventDefault()` to cancel the submission (the UI is restored automatically).
preventDefault(); // uncomment to cancel submission });
riaco_cp:unlock_success — fires after a successful AJAX response, before the container is replaced with unlocked content.
log('Unlocked:', instanceId, responseData); });
riaco_cp:unlock_error — fires on wrong password, rate-limit hit, or network/server failure.
warn('Unlock failed for', instanceId, errorMessage); });
License
This plugin is licensed under GPLv2 or later.