ID, $excluded_ids, true)) {
return true;
}
}
if (!empty($options['protected_post_types']) && is_array($options['protected_post_types'])) {
if (!in_array($post->post_type, $options['protected_post_types'], true)) {
return true;
}
}
return false;
}
/**
* Check if the current page is excluded from Watermarking.
* Checks watermark_excluded_page_ids.
*/
function accelvia_is_page_excluded_from_wm($options)
{
$post = get_post();
if (!$post) {
return false;
}
if (!empty($options['watermark_excluded_page_ids'])) {
$excluded_ids = array_map('absint', explode(',', $options['watermark_excluded_page_ids']));
if (in_array((int) $post->ID, $excluded_ids, true)) {
return true;
}
}
return false;
}
/**
* Enqueue the frontend protection script when appropriate.
*/
function accelvia_enqueue_frontend_protection()
{
// Never run in admin.
if (is_admin()) {
return;
}
$options = get_option(ACCELVIA_OPTION_KEY, array());
// Bail if protection is globally disabled.
if (empty($options['enable_protection']) || '1' !== $options['enable_protection']) {
return;
}
// Skip for logged-in administrators if that option is enabled.
if (!empty($options['skip_admins']) && '1' === $options['skip_admins'] && current_user_can('manage_options')) {
return;
}
$is_cp_excluded = accelvia_is_page_excluded_from_cp($options);
$is_wm_excluded = accelvia_is_page_excluded_from_wm($options);
if ($is_cp_excluded && $is_wm_excluded) {
return; // Nothing to do here.
}
// --- Content Protection Scripts ---
if (!$is_cp_excluded) {
// Enqueue the protection script.
wp_enqueue_script(
'accelvia-protection',
ACCELVIA_PLUGIN_URL . 'assets/js/protection.js',
array(), // No dependencies – pure Vanilla JS.
ACCELVIA_VERSION,
true // Load in footer.
);
// Pass configuration to JS.
$config = array(
'disableRightClick' => !empty($options['disable_right_click']) && '1' === $options['disable_right_click'],
'disableShortcuts' => !empty($options['disable_shortcuts']) && '1' === $options['disable_shortcuts'],
'disableTextSelection' => !empty($options['disable_text_selection']) && '1' === $options['disable_text_selection'],
'disableImageDrag' => !empty($options['disable_image_drag']) && '1' === $options['disable_image_drag'],
'disableCopy' => !empty($options['disable_copy']) && '1' === $options['disable_copy'],
'disableDevTools' => !empty($options['disable_devtools']) && '1' === $options['disable_devtools'],
'disableScreenshot' => !empty($options['disable_screenshot']) && '1' === $options['disable_screenshot'],
'encryptContent' => !empty($options['encrypt_content']) && '1' === $options['encrypt_content'],
'notificationType' => isset($options['notification_type']) ? $options['notification_type'] : 'toast',
'notificationMessage' => isset($options['notification_message'])
? $options['notification_message']
: __('This content is protected by Accelvia.', 'accelvia-content-protection'),
);
wp_localize_script('accelvia-protection', 'accelvia_config', $config);
} // End CP check
// --- Watermark Module ---
if (!$is_wm_excluded && !empty($options['watermark_enabled']) && '1' === $options['watermark_enabled']) {
wp_enqueue_script(
'accelvia-watermark',
ACCELVIA_PLUGIN_URL . 'assets/js/watermark.js',
array(), // No dependencies – pure Vanilla JS.
ACCELVIA_VERSION,
true // Load in footer.
);
$wm_config = array(
'type' => isset($options['watermark_type']) ? $options['watermark_type'] : 'text',
'imageUrl' => isset($options['watermark_image_url']) ? $options['watermark_image_url'] : '',
'text' => isset($options['watermark_text']) ? $options['watermark_text'] : __('© Protected by Accelvia', 'accelvia-content-protection'),
'fontSize' => isset($options['watermark_font_size']) ? absint($options['watermark_font_size']) : 16,
'fontColor' => isset($options['watermark_font_color']) ? $options['watermark_font_color'] : '#ffffff',
'position' => isset($options['watermark_position']) ? $options['watermark_position'] : 'bottom-right',
'opacity' => isset($options['watermark_opacity']) ? absint($options['watermark_opacity']) : 50,
'size' => isset($options['watermark_size']) ? absint($options['watermark_size']) : 30,
'tileSpacing' => isset($options['watermark_tile_spacing']) ? absint($options['watermark_tile_spacing']) : 80,
'scope' => isset($options['watermark_scope']) ? $options['watermark_scope'] : 'all',
'selector' => isset($options['watermark_selector']) ? $options['watermark_selector'] : '',
'excludeSelector' => isset($options['watermark_exclude_selector']) ? $options['watermark_exclude_selector'] : '',
'device' => isset($options['watermark_device']) ? $options['watermark_device'] : 'both',
);
wp_localize_script('accelvia-watermark', 'accelvia_watermark', $wm_config);
}
}
add_action('wp_enqueue_scripts', 'accelvia_enqueue_frontend_protection');
/**
* Inject an inline micro-script in
that blocks right-click IMMEDIATELY.
*
* This eliminates the race condition where protection.js hasn't loaded yet
* during hot-reload or slow page loads, leaving right-click unprotected.
*
* Also injects a block that hides page content when JavaScript
* is disabled, since all protections depend on JavaScript.
*/
function accelvia_inline_head_protection()
{
// Never run in admin.
if (is_admin()) {
return;
}
$options = get_option(ACCELVIA_OPTION_KEY, array());
// Bail if protection is globally disabled.
if (empty($options['enable_protection']) || '1' !== $options['enable_protection']) {
return;
}
// Skip for logged-in administrators if that option is enabled.
if (!empty($options['skip_admins']) && '1' === $options['skip_admins'] && current_user_can('manage_options')) {
return;
}
// Respect Content Protection exclusions for the head guard too.
if (accelvia_is_page_excluded_from_cp($options)) {
return;
}
// --- Inline micro-script: blocks right-click before body even renders ---
$inline_js = '';
if (!empty($options['disable_right_click']) && '1' === $options['disable_right_click']) {
$inline_js .= 'document.addEventListener("contextmenu",function(e){e.preventDefault();e.stopPropagation();return false;},true);';
}
if (!empty($options['disable_shortcuts']) && '1' === $options['disable_shortcuts']) {
$inline_js .= 'document.addEventListener("keydown",function(e){var k=e.keyCode||e.which;var c=e.ctrlKey||e.metaKey;var s=e.shiftKey;if(k===123||c&&s&&(k===73||k===74||k===67)||c&&k===85||c&&k===83||c&&k===80){e.preventDefault();e.stopPropagation();return false;}},true);';
}
if (!empty($options['disable_text_selection']) && '1' === $options['disable_text_selection']) {
$inline_js .= 'document.addEventListener("selectstart",function(e){e.preventDefault();},true);';
}
if (!empty($options['disable_devtools']) && '1' === $options['disable_devtools']) {
// Immediate DevTools detection before body parses.
$inline_js .= 'window._accelvia_dt=false;';
$inline_js .= 'var dt=function(){var a=new Date().getTime();debugger;if(new Date().getTime()-a>100){window._accelvia_dt=true;}};';
$inline_js .= 'dt();';
// If detected instantly, start an infinite debugger loop in head.
$inline_js .= 'if(window._accelvia_dt){setInterval(function(){debugger;},100);}';
}
if ($inline_js) {
echo '' . "\n"; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- Hardcoded inline JS, no user input.
}
// --- CSS: disable text selection immediately (before JS loads) ---
if (!empty($options['disable_text_selection']) && '1' === $options['disable_text_selection']) {
echo '' . "\n";
}
// --- Noscript guard: hide content if JavaScript is disabled ---
echo '' . "\n";
echo '' . "\n";
echo ' ' . "\n";
}
add_action('wp_head', 'accelvia_inline_head_protection', 1); // Priority 1 = very early.
/**
* Inject a message in the body when JavaScript is disabled.
*/
function accelvia_noscript_body_message()
{
// Never run in admin.
if (is_admin()) {
return;
}
$options = get_option(ACCELVIA_OPTION_KEY, array());
// Bail if protection is globally disabled.
if (empty($options['enable_protection']) || '1' !== $options['enable_protection']) {
return;
}
// Skip for logged-in administrators.
if (!empty($options['skip_admins']) && '1' === $options['skip_admins'] && current_user_can('manage_options')) {
return;
}
if (accelvia_is_page_excluded_from_cp($options)) {
return;
}
echo '';
echo '';
echo '
';
echo '
' . esc_html__('JavaScript Required', 'accelvia-content-protection') . ' ';
echo '
' . esc_html__('This website requires JavaScript to be enabled for content protection. Please enable JavaScript in your browser settings and reload the page.', 'accelvia-content-protection') . '
';
echo '
';
echo ' ' . "\n";
}
add_action('wp_body_open', 'accelvia_noscript_body_message', 1);
/**
* Server-side HTML minification to deter view-source: inspection.
*
* Strips HTML comments, collapses excessive whitespace, and removes
* blank lines from the output buffer. This makes view-source: show
* a wall of compressed code that's difficult to read.
*
* Cannot prevent view-source: access (browser-level feature) but
* makes the output significantly less useful to inspect.
*/
function accelvia_start_output_minification()
{
// Never run in admin, AJAX, REST, or cron.
if (is_admin() || wp_doing_ajax() || defined('REST_REQUEST') || wp_doing_cron()) {
return;
}
$options = get_option(ACCELVIA_OPTION_KEY, array());
// Bail if protection is globally disabled.
if (empty($options['enable_protection']) || '1' !== $options['enable_protection']) {
return;
}
// Skip for logged-in administrators.
if (!empty($options['skip_admins']) && '1' === $options['skip_admins'] && current_user_can('manage_options')) {
return;
}
if (accelvia_is_page_excluded_from_cp($options)) {
return;
}
ob_start('accelvia_minify_html_output');
}
/**
* Callback for ob_start — minifies and encodes the HTML output.
*
* Two-stage protection:
* 1. Minify: strip comments, collapse whitespace (makes source harder to read).
* 2. Encode: base64-encode the body content so view-source: shows gibberish.
* JavaScript decodes it at runtime for normal users.
*
* Search engine bots are excluded from encoding to preserve SEO.
*
* @param string $html Raw HTML output.
* @return string Protected HTML.
*/
function accelvia_minify_html_output($html)
{
if (empty($html)) {
return $html;
}
// Don't process non-HTML content (feeds, JSON, etc.).
if (strpos($html, ',