Initial commit: Atomaste website

This commit is contained in:
2025-12-10 12:17:30 -05:00
commit 0b9e5d1605
19260 changed files with 5206382 additions and 0 deletions

View File

@@ -0,0 +1,177 @@
<?php
defined('ABSPATH') or die("you do not have access to this page!");
if (!class_exists("cmplz_wsc_api")) {
class cmplz_wsc_api
{
private static $_this;
function __construct()
{
if (isset(self::$_this))
wp_die(sprintf('%s is a singleton class and you cannot create a second instance.', get_class($this)));
self::$_this = $this;
add_action('rest_api_init', array($this, 'wsc_scan_enable_webhook_api'));
}
static function this()
{
return self::$_this;
}
/**
* Register the REST API route for the WSC scan.
*
* This function registers a custom REST API route for the WSC scan. The route
* accepts only POST requests and uses the `wsc_scan_callback` method as the
* callback function.
*
* @return void
*/
public function wsc_scan_enable_webhook_api(): void
{
register_rest_route('complianz/v1', 'wsc-scan', array(
'methods' => 'POST', // Accept only POST requests
'callback' => array($this, 'wsc_scan_webhook_callback'),
'permission_callback' => '__return_true',
));
register_rest_route(
'complianz/v1',
'wsc-checks',
array(
'methods' => 'POST', // Accept only POST requests.
'callback' => array( $this, 'wsc_scan_webhook_checks_callback' ),
'permission_callback' => '__return_true',
)
);
}
/**
* Handle the WSC scan webhook checks callback.
*
* This function processes the WSC scan webhook checks callback. It validates the request
* and then processes the scan checks. If the request is invalid, an error is returned.
*
* @param WP_REST_Request $request The REST API request object.
* @return WP_REST_Response|WP_Error The REST API response object or an error object.
*/
public function wsc_scan_webhook_checks_callback( WP_REST_Request $request ) {
$error = self::wsc_scan_validate_request( $request, 'checks' );
$is_valid_request = empty( $error );
if ( ! $is_valid_request ) { // if the array is not empty, contains an error and the request is invalid.
return new WP_Error(
$error['code'],
$error['message'],
array( 'status' => $error['status'] )
);
}
$result = json_decode( $request->get_body() );
COMPLIANZ::$wsc_scanner->wsc_scan_process_checks( $result );
return new WP_REST_Response( 'Checks updated!', 200 );
}
/**
* Process the WSC scan webhook callback.
*
* This function processes the WSC scan webhook callback. It validates the request
* and then processes the scan results. If the request is invalid, an error is returned.
*
* @param WP_REST_Request $request The REST API request object.
* @return WP_REST_Response|WP_Error The REST API response object or an error object.
*/
public function wsc_scan_webhook_callback(WP_REST_Request $request)
{
$error = self::wsc_scan_validate_request( $request,'scan' );
$is_valid_request = empty($error); // if the array is empty, the request is valid
if (!$is_valid_request) { // if the array is not empty, contains an error and the request is invalid
return new WP_Error(
$error['code'],
$error['message'],
array('status' => $error['status'])
);
}
// start the processing of the request
$result = json_decode($request->get_body());
if (!isset($result->data->result->trackers) || !is_array($result->data->result->trackers) || count($result->data->result->trackers) === 0) {
return new WP_REST_Response('No cookies found in the result.', 200);
}
$current_wsc_status = get_option('cmplz_wsc_scan_status');
// if the scan is already completed, exit
if ($current_wsc_status === 'completed') {
return new WP_REST_Response('Scan already completed.', 200);
}
COMPLIANZ::$wsc_scanner->wsc_complete_cookie_scan( $result, true );
return new WP_REST_Response('Cookies updated!', 200);
}
/**
* Validate the WSC scan webhook request.
*
* This function validates the WSC scan webhook request. It checks if the request
* is valid and contains the necessary information to process the scan results.
*
* @param WP_REST_Request $request The REST API request object.
* @return array If the request is invalid an array containing the error details, otherwise an empty array.
*/
public static function wsc_scan_validate_request(WP_REST_Request $request, $type): array
{
// check the body
if (empty($request->get_body())) {
return [
'code' => 'invalid_request',
'message' => 'Request blocked: missing request.',
'status' => 400
];
}
// Get options for permission check
$scan_id = $type === 'scan' ? get_option('cmplz_wsc_scan_id', false) : get_option('cmplz_wsc_checks_scan_id',false);
$scan_created_at = $type === 'scan' ? get_option('cmplz_wsc_scan_createdAt', false) : get_option('cmplz_wsc_checks_scan_createdAt',false);
// Check if there is an active scan
if (!$scan_id || !$scan_created_at) {
return [
'code' => 'invalid_wsc_scan',
'message' => 'No active scan found.',
'status' => 400
];
}
// Check the user agent
$user_agent = $request->get_header('User-Agent');
if (strpos($user_agent, 'radar') === false) {
return [
'code' => 'invalid_user_agent',
'message' => 'Request blocked: unauthorized User-Agent.',
'status' => 400
];
}
// Verify scan status event in the request body
$data = json_decode($request->get_body());
if (!isset($data->event) || $data->event !== 'scan-completed') {
return [
'code' => 'invalid_event',
'message' => 'Request blocked: missing or invalid scan status.',
'status' => 400
];
}
// Return the errors array if any errors are found, or an empty array if all checks pass
return [];
}
}
}

View File

@@ -0,0 +1,621 @@
<?php
defined('ABSPATH') or die();
if (!class_exists("cmplz_wsc_auth")) {
class cmplz_wsc_auth
{
const WSC_ENDPOINT = 'aHR0cHM6Ly9hcGkuY29tcGxpYW56Lmlv';
const WSC_CB_ENDPOINT = 'aHR0cHM6Ly9leHRlcm5hbC1wdWJsaWMtZ2VuZXJhbC5zMy5ldS13ZXN0LTEuYW1hem9uYXdzLmNvbS9zdGF0dXMuanNvbg==';
const WSC_TERMS_ENDPOINT = 'aHR0cHM6Ly9jb29raWVkYXRhYmFzZS5vcmcvd3AtanNvbi93c2MvdjEvdGVybXM=';
const NEWSLETTER_TERMS_ENDPOINT = 'aHR0cHM6Ly9jb29raWVkYXRhYmFzZS5vcmcvd3AtanNvbi9uZXdzbGV0dGVyL3YxL3Rlcm1z';
const NEWSLETTER_SIGNUP_ENDPOINT = 'aHR0cHM6Ly9tYWlsaW5nbGlzdC5jb21wbGlhbnouaW8=';
const CONS_ENDPOINT = 'aHR0cHM6Ly9jb25zZW50LmNvbXBsaWFuei5pby9wdWJsaWMvY29uc2VudA==';
const CONS_ENDPOINT_PK = 'qw0Jv5legvI9fQdn5OvNedpG4zibaTNT';
const WSC_ENDPOINT_AUTH_HEADER = 'QmFzaWMgZEdWaGJXSnNkV1ZmYzNSaFoybHVaenBGYm05bVJHZzRjV0Y2YVhCemFUWkxSM05FVlE9PQ==';
const PARTNER_ID = 'NjQ1MTc4NjMtM2YzMS00NDA3LWJjMWUtMjc4MjNlOTJhNThl';
const CONS_IDENTIFIERS = [
'wsc_consent' => 'terms',
'newsletter_consent' => 'newsletter',
];
public function init_hooks()
{
add_action("admin_init", array($this, 'confirm_email_auth'), 10, 3); // Verify the authentication link in the email
add_action('cmplz_every_day_hook', array($this, 'check_failed_consent_onboarding'));
add_action('cmplz_every_day_hook', array($this, 'check_failed_newsletter_signup'));
}
/**
* Sends an authentication email.
*
* This function sends an authentication email to the specified email address.
* It first checks if the user has the capability to manage the plugin.
* If the email is not a valid email address, it updates an option to indicate that the email was not sent.
* If the email is valid, it makes a POST request to the WSC endpoint to send the email.
* If the request is successful, it sets various options to indicate that the email was sent and updates the signup status.
* If the request fails, it updates an option to indicate that the email was not sent.
*
* @param string $email The email address to send the authentication email to.
* @return void
*/
public static function send_auth_email(string $email): void
{
if (!cmplz_user_can_manage() || empty($email)) {
return;
}
if (!is_email($email)) {
update_option('cmplz_wsc_error_email_not_sent', true, false);
return;
}
$wsc_endpoint = base64_decode(self::WSC_ENDPOINT);
$wsc_endpoint_auth_header = base64_decode(self::WSC_ENDPOINT_AUTH_HEADER);
$partner_id = base64_decode(self::PARTNER_ID);
$request = wp_remote_post(
$wsc_endpoint . '/api/lite/users',
array(
'headers' => array(
'Content-Type' => 'application/json',
'Authorization' => $wsc_endpoint_auth_header,
),
'timeout' => 15,
'sslverify' => true,
'body' => json_encode(array(
'email' => sanitize_email($email),
"base_url" => esc_url_raw(admin_url()),
"partner" => $partner_id
))
)
);
if (is_wp_error($request)) {
$error_message = $request->get_error_message();
if (WP_DEBUG) {
error_log('COMPLIANZ: cannot send email, request failed');
if ($error_message) {
error_log('COMPLIANZ: ' . $error_message);
}
}
update_option('cmplz_wsc_error_email_not_sent', true, false);
} else {
$response_code = wp_remote_retrieve_response_code($request);
if ($response_code === 200) {
cmplz_update_option_no_hooks(cmplz_wsc::WSC_EMAIL_OPTION_KEY, $email);
update_option('cmplz_wsc_signup_status', 'pending', false);
update_option('cmplz_wsc_status', 'pending', false);
update_option('cmplz_wsc_signup_date', time(), false);
delete_option('cmplz_wsc_error_email_not_sent');
delete_option( cmplz_wsc::WSC_OPT_ONBOARDING_DATE );
} else {
$response_message = wp_remote_retrieve_response_message($request);
if (WP_DEBUG) {
error_log('COMPLIANZ: cannot send email, request failed');
if ($response_message) {
error_log('COMPLIANZ: ' . $response_message);
}
}
update_option('cmplz_wsc_error_email_not_sent', true, false);
}
}
}
/**
* Handles the confirmation of email authentication for the Website Scan Feature.
*
* This function is responsible for confirming the email authentication for the Complianz plugin.
* It checks if the user has the necessary permissions, if the page is the Complianz page,
* and if the lite-user-confirmation parameter is set. It then verifies the email and token,
* makes a request to the WSC endpoint, and updates the necessary options accordingly.
* Finally, it redirects the user to the Complianz settings page.
*
* @return void
*/
public function confirm_email_auth(): void
{
if (!cmplz_user_can_manage()) {
return;
}
if (!isset($_GET['page']) || $_GET['page'] !== 'complianz') {
return;
}
if (!isset($_GET['lite-user-confirmation'])) {
return;
}
$stored_email = cmplz_get_option(cmplz_wsc::WSC_EMAIL_OPTION_KEY);
if (!isset($_GET['email']) || $_GET['email'] !== $stored_email) {
update_option('cmplz_wsc_error_email_mismatch', true, false);
if (WP_DEBUG) {
error_log('COMPLIANZ: email does not match the stored email');
}
return;
}
if (!isset($_GET['token'])) {
update_option('cmplz_wsc_error_missing_token', true, false);
if (WP_DEBUG) {
error_log('COMPLIANZ: token not found in the authentication url');
}
return;
}
$token = sanitize_text_field($_GET['token']);
$wsc_endpoint = base64_decode(self::WSC_ENDPOINT);
$wsc_endpoint_auth_header = base64_decode(self::WSC_ENDPOINT_AUTH_HEADER);
$request = wp_remote_post($wsc_endpoint . '/api/lite/oauth_applications', array(
'headers' => array(
'Content-Type' => 'application/json',
'Authorization' => $wsc_endpoint_auth_header,
),
'timeout' => 15,
'sslverify' => true,
'body' => json_encode(
array(
'email' => sanitize_title($stored_email),
'token' => $token,
)
),
));
if (is_wp_error($request)) {
$error_message = $request->get_error_message();
if (WP_DEBUG) {
error_log('COMPLIANZ: cannot confirm email, request failed');
if ($error_message) {
error_log('COMPLIANZ: ' . $error_message);
}
}
update_option('cmplz_wsc_error_email_auth_failed', true, false);
} else {
$response_code = wp_remote_retrieve_response_code($request);
if ($response_code === 201) {
$response_body = json_decode(wp_remote_retrieve_body($request));
if (isset($response_body->client_id) && isset($response_body->client_secret)) {
cmplz_update_option_no_hooks(cmplz_wsc::WSC_CLIENT_ID_OPTION_KEY, $response_body->client_id);
cmplz_update_option_no_hooks(cmplz_wsc::WSC_CLIENT_SECRET_OPTION_KEY, $response_body->client_secret);
update_option('cmplz_wsc_signup_status', 'enabled', false);
update_option('cmplz_wsc_status', 'enabled', false);
update_option('cmplz_wsc_auth_completed', true, false);
cmplz_wsc_onboarding::update_onboarding_status('terms', true);
delete_option('cmplz_wsc_error_email_auth_failed');
delete_option('cmplz_wsc_error_email_mismatch');
delete_option('cmplz_wsc_error_missing_token');
// reset the processed pages
delete_transient('cmplz_processed_pages_list');
} else {
if (WP_DEBUG) {
error_log('COMPLIANZ: cannot confirm email, client id or secret not found in response');
}
update_option('cmplz_wsc_error_email_auth_failed', true, false);
}
} else {
if (WP_DEBUG) {
error_log('COMPLIANZ: cannot confirm email, request failed');
}
update_option('cmplz_wsc_error_email_auth_failed', true, false);
}
}
wp_redirect(cmplz_admin_url('#settings/settings-cd'));
exit;
}
/**
* Retrieves the access token for the Website Scan feature.
*
* This function checks the WSC signup status and retrieves the access token
* if it is available. If the token is not found, it tries to retrieve a fresh one
* using the provided email, client ID, and client secret.
*
* @param bool $new Whether to retrieve a new token.
* @param bool $no_store Whether to store the token.
* @param array|false $client_credentials The client credentials.
*
* @return string|bool The access token if available, 'pending' if the WSC signup status is pending,
* false if the email, client ID, or client secret is not found, or false if there
* was an error retrieving the token.
*
*/
public static function get_token($new = false, $no_store = false, $client_credentials = false)
{
// emulating the union type array|false $client_credentials
if (!is_bool($new)) {
throw new InvalidArgumentException('$new needs to be of type bool');
}
if (!is_bool($no_store)) {
throw new InvalidArgumentException('$no_store needs to be of type bool');
}
if ($client_credentials !== false && !is_array($client_credentials)) {
throw new InvalidArgumentException('$client_credentials must be an array or false');
}
// clear stored token
if ($new) cmplz_delete_transient('cmplz_wsc_access_token');
$token = cmplz_get_transient('cmplz_wsc_access_token');
if ($token) {
return $token;
}
//if no token found, try retrieving a fresh one
$email = (string)cmplz_get_option(cmplz_wsc::WSC_EMAIL_OPTION_KEY);
$client_id = (string)cmplz_get_option(cmplz_wsc::WSC_CLIENT_ID_OPTION_KEY);
$client_secret = (string)cmplz_get_option(cmplz_wsc::WSC_CLIENT_SECRET_OPTION_KEY);
// if client credentials are provided, use them
if ($client_credentials) {
$client_id = $client_credentials['client_id'];
$client_secret = $client_credentials['client_secret'];
} else {
if ($email === '' || $client_id === '' || $client_secret === '') {
// if (WP_DEBUG) {
// error_log('COMPLIANZ: cannot retrieve token, email or client id or secret not found');
// }
return false;
}
}
$wsc_endpoint = base64_decode(self::WSC_ENDPOINT);
$wsc_endpoint_auth_header = base64_decode(self::WSC_ENDPOINT_AUTH_HEADER);
$request = wp_remote_post(
$wsc_endpoint . '/oauth/token',
array(
'headers' => array(
'Content-Type' => 'application/json',
'Authorization' => $wsc_endpoint_auth_header,
),
'timeout' => 15,
'sslverify' => true,
'body' => json_encode(
array(
'grant_type' => "client_credentials",
"client_id" => $client_id,
"client_secret" => $client_secret,
"scope" => "write"
)
)
)
);
if (!is_wp_error($request)) { // request success true
$request = json_decode(wp_remote_retrieve_body($request));
if (isset($request->access_token)) { // if there's an access token
if ($no_store) return $request->access_token;
delete_option('cmplz_wsc_error_token_api');
update_option('cmplz_wsc_connection_updated', time(), false);
$token = $request->access_token;
$expires = $request->expires_in ?? 7200;
cmplz_set_transient('cmplz_wsc_access_token', $token, $expires - 10);
return $token;
} else {
if ($no_store) return false;
update_option('cmplz_wsc_error_token_api', true, false);
if (WP_DEBUG && $request->error) {
error_log('COMPLIANZ: cannot retrieve token, token not found in response');
}
return false;
}
} else {
if (!$no_store) update_option('cmplz_wsc_error_token_api', true, false);
$error_message = $request->get_error_message();
if (WP_DEBUG) {
error_log('COMPLIANZ: cannot retrieve token, request failed');
if ($error_message) {
error_log('COMPLIANZ: ' . $error_message);
}
}
return false;
}
}
/**
* Store the consent when user signs up for the WSC Feature
* or when the user signs up for the newsletter
*
* The method is triggered once using the cron job during the onboarding process
* or using check_failed_consent_onboarding() method ($retry = true)
*
* @param string $type || Could be wsc terms, wsc newsletter 'wsc_consent' // 'newsletter_consent'
* @param array $posted_data
* @param bool $retry
* @param string $consent_data
* @return void
*/
public static function store_onboarding_consent(string $type, array $posted_data, bool $retry = false, string $consent_data = ''): void
{
// Check if the given type exists in the cons_identifiers array.
if (!array_key_exists($type, self::CONS_IDENTIFIERS)) {
return;
}
// Check if the posted_data array is empty.
if (empty($posted_data)) {
return;
}
// if it's a retry because there's an old failed store attempts
// set the old consent
if ($retry) {
$consent = $consent_data;
} else {
// else let's create a new consent data
// check posted data
$email = sanitize_email($posted_data['email']);
if (!is_email($email)) {
return;
}
// Create a subject id
$site_url = site_url();
$encodedSiteUrl = base64_encode($site_url);
$encodedEmail = base64_encode($email);
$consent_subject_id = sprintf('cmplz-%s#%s', $encodedSiteUrl, $encodedEmail);
// Check for timestamp and url
$timestamp = isset($posted_data['timestamp']) // check if timestamp is set
? (int)$posted_data['timestamp'] / (strlen($posted_data['timestamp']) > 10 ? 1000 : 1) // if timestamp is in milliseconds, convert to seconds
: time(); // if $posted_data['timestamp'] is not set, use the current time
$url = esc_url_raw($posted_data['url']) ?? site_url();
// Generate the consent
$consent = json_encode([
'timestamp' => date('c', $timestamp),
'subject' => [
'id' => $consent_subject_id,
'email' => $email,
],
'preferences' => [
$type => true
],
'legal_notices' => [
[
'identifier' => self::CONS_IDENTIFIERS[$type] // terms or newsletter
]
],
'proofs' => [
[
// pass all $posted_data as content
'content' => json_encode([
'email' => $email,
'timestamp' => $timestamp,
'url' => $url,
]),
'form' => 'complianz-onboarding__' . $type, // complianz onboarding form ??
]
],
]);
}
// safe store the consent locally
update_option('cmplz_' . $type . '_consentdata', $consent, false);
$cons_endpoint = base64_decode(self::CONS_ENDPOINT);
// Send the request
$request = wp_remote_post(
$cons_endpoint,
array(
'headers' => array(
'Content-Type' => 'application/json',
'ApiKey' => self::CONS_ENDPOINT_PK,
),
'timeout' => 15,
'sslverify' => true,
'body' => $consent
)
);
if (is_wp_error($request)) {
$error_message = $request->get_error_message();
if (WP_DEBUG) {
error_log('COMPLIANZ: cannot store consent, request failed for identifier: ' . $type);
if ($error_message) {
error_log('COMPLIANZ: ' . $error_message);
}
}
// // define an error into the options
update_option('cmplz_consent_error_timestamp_' . $type, time());
// store the consent for the time we can resend the request
update_option('cmplz_consent_error_consentdata_' . $type, $consent);
} else {
$response_code = wp_remote_retrieve_response_code($request);
if ($response_code == 200) {
delete_option('cmplz_consent_' . $type);
// delete possible consent errors
delete_option('cmplz_consent_error_timestamp_' . $type);
delete_option('cmplz_consent_error_consentdata_' . $type);
$body = json_decode(wp_remote_retrieve_body($request));
// store the consent locally
update_option('cmplz_consent_' . $type, $body);
} else {
$response_message = wp_remote_retrieve_response_message($request);
if (WP_DEBUG) {
error_log('COMPLIANZ: cannot store consent, request failed for identifier: ' . $type);
if ($response_message) {
error_log('COMPLIANZ: ' . $response_message);
}
}
// // define an error into the options
update_option('cmplz_consent_error_timestamp_' . $type, time());
// store the consent for the time we can resend the rquest
update_option('cmplz_consent_error_consentdata_' . $type, $consent);
}
}
}
/**
* Subscribes a user to the newsletter.
*
* @param string $email The email address of the user.
* @param bool $retry Whether to retry the subscription if it fails.
* @return void
*/
public static function newsletter_sign_up(string $email, bool $retry = false): void
{
$license_key = '';
if (defined('rsssl_pro_version')) {
$license_key = COMPLIANZ::$license->license_key();
$license_key = COMPLIANZ::$license->maybe_decode($license_key);
}
$api_params = array(
'has_premium' => defined('cmplz_premium'), // not required
'license' => $license_key, // not required
'email' => sanitize_email($email),
'domain' => esc_url_raw(site_url()),
);
$newsletter_signup_endpoint = base64_decode(self::NEWSLETTER_SIGNUP_ENDPOINT);
$request = wp_remote_post($newsletter_signup_endpoint, array('timeout' => 15, 'sslverify' => true, 'body' => $api_params));
if (is_wp_error($request)) {
update_option('cmplz_newsletter_signup_error_email', $email, false); // save the email in an option
update_option('cmplz_newsletter_signup_error', true, false); // save the failed attempt
update_option('cmplz_newsletter_signup_error_timestamp', time(), false); // set an error with the timestamp
// log the error
if (WP_DEBUG) {
$error_message = $request->get_error_message();
if ($error_message) {
error_log('COMPLIANZ: ' . $error_message);
}
}
} else {
$response_code = wp_remote_retrieve_response_code($request); // 200 ok
if ($response_code === 200) {
// if the method is called by the cron or there's a mismatch between the emails clean the options
if ($retry || $email !== get_option('cmplz_newsletter_signup_error_email')) {
// remove any failed attempts
delete_option('cmplz_newsletter_signup_error_email');
delete_option('cmplz_newsletter_signup_error');
delete_option('cmplz_newsletter_signup_error_timestamp');
}
// save the email in the options
cmplz_update_option_no_hooks('notifications_email_address', $email); // save the email in the options
cmplz_update_option_no_hooks('send_notifications_email', 1); // enable the notifications
cmplz_wsc_onboarding::update_onboarding_status('newsletter', true);
}
}
}
/**
* Website Scan Circuit Breaker
*
* This function checks if the Website scan endpoint accepts user signups and radar scans
* passing auth or scanner as $service.
*
* @param string $service The service to check | signup or scanner.
* @return bool Returns true if the Website scan endpoint accepts user signups, false otherwise.
*
*/
public static function wsc_api_open(string $service): bool
{
$wsc_cb_endpoint = base64_decode(self::WSC_CB_ENDPOINT);
$request = wp_remote_get($wsc_cb_endpoint);
if (is_wp_error($request)) {
cmplz_wsc_logger::log_errors( 'wsc_api_open', $request->get_error_message() );
return false;
}
$service = sprintf('%s_enabled', $service);
$response_body = json_decode(wp_remote_retrieve_body($request));
if (isset($response_body->$service) && $response_body->$service === 'true') {
return true;
}
return false;
}
/**
* Check for failed onboarding consent store attempts
* If there's a failed attempt, try to store it again
*
*
* @return void
*/
public function check_failed_consent_onboarding(): void
{
$identifiers = self::CONS_IDENTIFIERS;
foreach ($identifiers as $key => $type) {
// check for the errors
$error_timestamp = get_option('cmplz_consent_error_timestamp_' . $key, false);
// store the consent for the time we can resend the rquest
$error_consentdata = get_option('cmplz_consent_error_consentdata_' . $key, false);
if ($error_consentdata && $error_timestamp < time() - 68400) {
$this->store_onboarding_consent($key, [], true, $error_consentdata);
}
}
}
/**
* Check for failed newsletter signups
* If there's a failed attempt, try to sign up again
*
* @return bool
*/
public function check_failed_newsletter_signup(): bool
{
$failed = get_option('cmplz_newsletter_signup_error');
$timestamp = get_option('cmplz_newsletter_signup_error_timestamp');
$email = get_option('cmplz_newsletter_signup_error_email');
if ($failed && $timestamp && $email) {
// check if the error is older than 24 hours
if ($timestamp < time() - 86400) {
// try to sign up again
self::newsletter_sign_up($email, true);
}
}
return true;
}
/**
* Checks if the WSC (Website Scan) is authenticated.
*
* This method verifies if the WSC is authenticated by checking if the client ID and client secret
* are stored in the options. If either the client ID or client secret is empty, it returns false.
* Otherwise, it returns true indicating that the WSC is authenticated.
*
* @return bool Returns true if the WSC is authenticated, false otherwise.
*/
public static function wsc_is_authenticated(): bool {
$client_id = (string) cmplz_get_option( cmplz_wsc::WSC_CLIENT_ID_OPTION_KEY );
$client_secret = (string) cmplz_get_option( cmplz_wsc::WSC_CLIENT_SECRET_OPTION_KEY );
if ( empty( $client_id ) || empty( $client_secret ) ) {
return false;
}
return true;
}
}
}

View File

@@ -0,0 +1,72 @@
<?php
defined('ABSPATH') or die();
if (!class_exists("cmplz_wsc_logger")) {
class cmplz_wsc_logger
{
public function init_hooks()
{
add_action( 'cmplz_every_month_hook', array( $this, 'clear_errors_log') );
}
/**
* Logs an error related to a specific $context and stores it in a WordPress option.
*
* @param string $context The $context name or identifier related to the error.
* @param string $error_message The error message to log.
*/
public static function log_errors(string $context, string $error_message = ''): void
{
// If WP_DEBUG is enabled, log the error to the error log
if (defined('WP_DEBUG') && WP_DEBUG) {
error_log("COMPLIANZ: error in context '$context': " . $error_message);
}
// Get existing errors from the options table
$errors = get_option('cmplz_wsc_logs', array());
$sanitized_context = sanitize_text_field($context);
$sanitized_error_message = sanitize_text_field($error_message);
$sanitized_timestamp = current_time('mysql');
// Append the new error
$errors[] = array(
'context' => $sanitized_context,
'error_message' => $sanitized_error_message,
'timestamp' => $sanitized_timestamp
);
$sanitized_errors = array_map( function( $error ) {
return array(
'context' => sanitize_text_field( $error['context'] ),
'error_message' => sanitize_text_field( $error['error_message'] ),
'timestamp' => sanitize_text_field( $error['timestamp'] ),
);
}, $errors );
// Update the option with the new error log
update_option('cmplz_wsc_logs', $sanitized_errors, false);
}
/**
* Retrieves all logged errors from the WordPress options.
*
* @return array The array of logged errors.
*/
public function get_errors_log(): array
{
// Retrieve the errors stored in the WordPress option
return get_option('cmplz_wsc_logs', array());
}
/**
* Clears all logged errors from the WordPress options.
*/
public function clear_errors_log(): void
{
// Delete the option to clear all stored errors
delete_option('cmplz_wsc_logs');
}
}
}

View File

@@ -0,0 +1,172 @@
<?php
defined('ABSPATH') or die();
if (!class_exists("cmplz_wsc_notices")) {
class cmplz_wsc_notices
{
public function init_hooks()
{
// If any hooks are needed for notices
add_filter('cmplz_field_notices', array($this, 'notices'));
add_filter('cmplz_warning_types', array($this, 'wsc_scan_add_warnings'));
}
/**
* Push some error messages if we find any
*
* @param array $notices
*
* @return array
*/
public function notices(array $notices): array
{
if (!cmplz_user_can_manage()) {
return $notices;
}
if (get_option('cmplz_wsc_error_email_mismatch')) {
$notices[] = [
'field_id' => cmplz_wsc::WSC_EMAIL_OPTION_KEY,
'label' => 'warning',
'title' => __("E-mail mismatch", 'complianz-gdpr'),
'text' => __("The e-mail that you are authenticating does not match the e-mail stored in your settings currently. Please clear the e-mail, save, then enter your e-mail address again.", 'complianz-gdpr'),
];
}
if (get_option('cmplz_wsc_error_missing_token')) {
$notices[] = [
'field_id' => cmplz_wsc::WSC_EMAIL_OPTION_KEY,
'label' => 'warning',
'title' => __("Missing token", 'complianz-gdpr'),
'text' => __("The token is missing from the URL which you are using to authenticate.", 'complianz-gdpr'),
'url' => 'https://complianz.io/authentication-failed',
];
}
if (get_option('cmplz_wsc_error_email_auth_failed')) {
$notices[] = [
'field_id' => cmplz_wsc::WSC_EMAIL_OPTION_KEY,
'label' => 'warning',
'title' => __("Authentication failed", 'complianz-gdpr'),
'text' => __("The authentication of your e-mail address failed. Please try again later.", 'complianz-gdpr'),
'url' => 'https://complianz.io/authentication-failed',
];
}
if (get_option('cmplz_wsc_error_token_api')) {
$notices[] = [
'field_id' => cmplz_wsc::WSC_EMAIL_OPTION_KEY,
'label' => 'warning',
'title' => __("Token not retrieved", 'complianz-gdpr'),
'text' => __("The token for the api could not be retrieved.", 'complianz-gdpr'),
'url' => 'https://complianz.io/authentication-failed',
];
}
if (get_option('cmplz_wsc_error_email_not_sent')) {
$notices[] = [
'field_id' => cmplz_wsc::WSC_EMAIL_OPTION_KEY,
'label' => 'warning',
'title' => __("E-mail verification not sent", 'complianz-gdpr'),
'text' => __("The e-mail to verify your e-mail address could not be sent. Please check your e-mail address or try again later.", 'complianz-gdpr'),
'url' => 'https://complianz.io/authentication-failed',
];
}
if (!cmplz_wsc_auth::wsc_is_authenticated()) {
$notices[] = [
'field_id' => cmplz_wsc::WSC_EMAIL_OPTION_KEY,
'label' => 'warning',
'title' => __("Try our new Website Scan!", 'complianz-gdpr'),
'text' => __("In the latest release of Complianz, we introduce our newest Website Scan. This scan will not only retrieve services and cookies but also help you configure our plugin and keep you up-to-date if changes are made that might need legal changes.", 'complianz-gdpr'),
'url' => 'https://complianz.io/about-the-website-scan'
];
}
if (!cmplz_wsc_auth::wsc_is_authenticated()) {
$notices[] = [
'field_id' => 'cookie_scan',
'label' => 'warning',
'title' => __("Try our new Website Scan!", 'complianz-gdpr'),
'text' => __("In the latest release of Complianz, we introduce our newest Website Scan. This scan will not only retrieve services and cookies but also help you configure our plugin and keep you up-to-date if changes are made that might need legal changes.", 'complianz-gdpr'),
'url' => '#settings/settings-cd',
];
}
if (get_option('cmplz_wsc_signup_status') === 'pending') {
$notices[] = [
'field_id' => cmplz_wsc::WSC_EMAIL_OPTION_KEY,
'label' => 'warning',
'title' => __("Check your email!", 'complianz-gdpr'),
'text' => __("Your authentication is still on pending, check your emails for a confirmation.", 'complianz-gdpr'),
'url' => 'https://complianz.io/about-the-website-scan#pending'
];
}
return $notices;
}
/**
* Add a warning that integrations changed.
*
* @param array $warnings
*
* @return array
*/
public function wsc_scan_add_warnings(array $warnings): array {
$wsc_checks_warnings = $this->retrieve_wsc_checks_warnings();
if ( is_array( $wsc_checks_warnings ) && count( $wsc_checks_warnings ) > 0 ) {
$warnings = array_merge( $warnings, $wsc_checks_warnings );
}
// if not authenticated.
if ( cmplz_wsc_auth::wsc_is_authenticated() ) {
return $warnings;
}
$warnings['wsc-scan'] = array(
'plus_one' => true,
'dismissible' => true,
'warning_condition' => '_true_',
'open' => __('You have a new feature! To enable the new and improved Website Scan you need to authenticate your website.', 'complianz-gdpr'),
'url' => '#settings/settings-cd',
);
return $warnings;
}
/**
* Retrieve warnings from the WSC checks.
*
* This method retrieves the warnings from the WSC checks by fetching the detections,
* checking if they match the notification blocks for the current Complianz version,
* and then creating an array of warnings based on these detections.
*
* @return array The array of warnings retrieved from the WSC checks.
*/
private function retrieve_wsc_checks_warnings(): array {
$warnings = array();
$detections = COMPLIANZ::$wsc_scanner->wsc_checks_retrieve_detections();
if ( is_array( $detections ) && count( $detections ) > 0 ) {
$blocks = COMPLIANZ::$wsc_scanner->wsc_checks_notification_blocks();
$cmplz_version = COMPLIANZ::$wsc_scanner->get_cmplz_version();
foreach ( $detections as $detection ) {
if ( isset( $blocks[ $detection['block'] ][ $cmplz_version ] ) ) {
$block = $blocks[ $detection['block'] ][ $cmplz_version ];
$warnings[ 'wsc-scan_' . $detection['block'] ] = array(
'plus_one' => false,
'dismissible' => true,
'warning_condition' => '_true_',
$block['type'] => COMPLIANZ::$wsc_scanner->wsc_checks_notification_generate_block_description( $block, $detection, true ),
'url' => $block['read_more'],
);
}
}
}
return $warnings;
}
}
}

View File

@@ -0,0 +1,669 @@
<?php
defined('ABSPATH') or die();
if (!class_exists("cmplz_wsc_onboarding")) {
class cmplz_wsc_onboarding
{
const WSC_MAX_DISMISS = 2;
const CMPLZ_PLUGIN_SLUG = 'complianz-gdpr';
public function init_hooks()
{
add_action("cmplz_do_action", array($this, 'handle_onboarding_action'), 10, 3);
add_action("admin_init", array($this, 'check_onboarding_status'), 10);
add_action("admin_init", array($this, 'maybe_show_onboarding_modal'), 20);
add_action("cmplz_every_week_hook", array($this, 'check_wsc_consent'), 20);
// Check if the option already exists, if not, set it up
if (!get_option('cmplz_wsc_onboarding_status')) {
$this->set_onboarding_status_option();
}
add_action('cmplz_store_wsc_onboarding_consent', array($this, 'cmplz_store_wsc_onboarding_consent_handler'), 10, 2);
add_action( 'upgrader_process_complete', array( $this, 'handle_onboarding_dismiss_on_upgrade' ), 10, 2 );
add_action( 'automatic_updates_complete', array( $this, 'handle_onboarding_dismiss_on_autoupdate' ) );
}
/**
* Sets the onboarding status option.
*
* This method initializes the onboarding status option with default values for 'terms', 'newsletter', and 'plugins'.
* It updates the 'cmplz_wsc_onboarding_status' option in the WordPress database with these default values.
*
* @return void
*/
private function set_onboarding_status_option(): void
{
$cmplz_wsc_onboarding_status = [
'terms' => false,
'newsletter' => false,
'plugins' => false,
];
update_option('cmplz_wsc_onboarding_status', $cmplz_wsc_onboarding_status, false);
}
/**
* Handles various onboarding actions.
*
* This method is responsible for handling different actions related to onboarding.
* It checks the user's capability to manage, and based on the action provided,
* performs the necessary operations such as sending authentication emails,
* resetting website scan, enabling or disabling the website scan, checking token status,
* and signing up for the newsletter.
*
* @param array $data The data associated with the action.
* @param string $action The action to be performed.
* @param WP_REST_Request $request The REST request object.
* @return array The updated data after performing the action.
*/
public function handle_onboarding_action(array $data, string $action, WP_REST_Request $request): array
{
if (!cmplz_user_can_manage()) {
return [];
}
switch ($action) {
// used on onboarding to sign up
case 'signup_wsc':
$posted_data = $request->get_json_params();
$email = sanitize_email($posted_data['email']);
if (is_email($email)) {
cmplz_wsc_auth::send_auth_email($email);
// Schedule storing onboarding consent asynchronously
self::schedule_store_onboarding_consent('cmplz_store_wsc_onboarding_consent', 1000, ['wsc_consent', $posted_data]);
}
break;
case 'get_wsc_terms':
$data = $this->get_onboarding_doc('wsc_terms');
break;
case 'dismiss_wsc_onboarding':
$posted_data = $request->get_json_params();
$step = sanitize_text_field( $posted_data['step'] );
$this->store_onboarding_dismiss( $step );
break;
case 'get_newsletter_terms':
$data = $this->get_onboarding_doc('newsletter');
break;
case 'get_recommended_plugins_status':
$posted_data = $request->get_json_params();
$plugins = $posted_data['plugins'] ?? [];
$data = [
'plugins' => $this->get_recommended_plugins_status($plugins),
'isUpgrade' => get_option('cmplz_upgraded_to_7', false)
];
break;
case 'install_plugin':
case 'activate_plugin':
$posted_data = $request->get_json_params();
$data = [
'plugins' => $this->process_plugin_action($action, $posted_data),
];
break;
}
return $data;
}
/**
* Check if the user should get the onboarding modal, for the signup process.
*
* @return void
*/
public function maybe_show_onboarding_modal(): void
{
if (!cmplz_user_can_manage()) {
return;
}
if ( ! isset( $_GET['websitescan'] ) && isset( $_GET['page'] ) && strpos( $_GET['page'], 'complianz' ) !== false && $this->should_onboard() ) {
wp_redirect( add_query_arg( ['websitescan' => ''], cmplz_admin_url() ) );
exit;
}
}
/**
* Determines whether the user should be onboarded.
*
* This function checks various conditions to determine if the user should be onboarded.
* If the user can't manage, or if the 'cmplz_force_signup' parameter is set in the URL,
* the function returns true. If the onboarding process is already complete or if the
* WSC API is not open, the function returns false. Otherwise, it checks if the onboarding
* start date is set and if it is earlier than the current time, and returns the result.
*
* @return bool Returns true if the user should be onboarded, false otherwise.
*/
private function should_onboard(): bool
{
if (!cmplz_user_can_manage()) {
return false;
}
// Force the signup, even if the user is already onboarded
if (isset($_GET['cmplz_force_signup'])) {
$cb_wsc_signup_status = cmplz_wsc_auth::wsc_api_open('signup');
if (!$cb_wsc_signup_status) {
cmplz_wsc_logger::log_errors('wsc_api_open', 'COMPLIANZ: WSC API is not open');
return false;
}
return true;
}
// if already onboarded.
if ( cmplz_wsc_auth::wsc_is_authenticated() ) {
return false;
}
// If the WSC has been either reset or dismissed during the onboarding.
if ( get_option( 'cmplz_wsc_reset_complete', false ) ) {
return false;
}
$is_dismissed = $this->wsc_is_dismissed();
if ( $is_dismissed ) {
COMPLIANZ::$wsc_scanner->wsc_scan_forced();
return false;
}
$onboarding_date = get_option( cmplz_wsc::WSC_OPT_ONBOARDING_DATE, false );
if ( ! $onboarding_date ) {
return false;
}
if ( $onboarding_date < time() ) { // If the onboarding date is in the past, show the onboarding modal.
$cb_wsc_signup_status = cmplz_wsc_auth::wsc_api_open( 'signup' );
if ( ! $cb_wsc_signup_status ) {
cmplz_wsc_logger::log_errors( 'wsc_api_open', 'COMPLIANZ: the user can onboard but WSC API is not open' );
return false;
}
return true;
}
return false;
}
/**
* Check and update the onboarding status.
*
* This method checks if the user is already onboarded or if the onboarding process has been dismissed.
* If the user is already onboarded, it logs a message and returns.
* If the onboarding process has been dismissed twice, it locks all scans and returns.
* Otherwise, it sets an onboarding date if it doesn't exist, or adjusts the date based on various conditions.
*
* @return void
*/
public function check_onboarding_status(): void {
// Return if already onboarded.
$is_onboarded = cmplz_wsc_auth::wsc_is_authenticated();
if ( $is_onboarded ) {
return;
}
$is_dismissed = $this->wsc_is_dismissed();
if ( $is_dismissed ) { // if reached the max attempts do not set onboarding_start.
return;
}
$onboarding_date = (int) get_option( cmplz_wsc::WSC_OPT_ONBOARDING_DATE, false );
$now = time();
$staged_end = strtotime( cmplz_wsc::WSC_ONBOARDING_STAGED_END );
// Set an onboarding date if it doesn't exist, between 120 seconds and 14 days from now.
if ( ! $onboarding_date ) {
$new_date = $now + wp_rand( 120, 14 * DAY_IN_SECONDS );
$this->set_onboarding_date( $new_date );
return;
}
// Here the onboarding date is already set.
// If the onboarding date is in the past or within the staged rollout period, do nothing.
if ( $onboarding_date < $now || $onboarding_date <= $staged_end ) {
return;
}
// Here the onboarding date is > $staged_end.
// Calculate the time difference between onboarding_date and staged_end.
$time_to_onboard = $onboarding_date - $staged_end;
// If $now is past $staged_end and the difference is less than 15 days, keep the existing date.
if ( $now > $staged_end && $time_to_onboard < 15 * DAY_IN_SECONDS ) {
return;
}
// If $now is past $staged_end and the difference is more than 30 days, randomize within the next 2 weeks.
if ( $now > $staged_end && $time_to_onboard > 30 * DAY_IN_SECONDS ) {
$new_date = $now + wp_rand( 1, 14 ) * DAY_IN_SECONDS;
$this->set_onboarding_date( $new_date );
return;
}
// If $now is past $staged_end and the difference is between 15 and 30 days, randomize within the next week.
if ( $now > $staged_end && $time_to_onboard <= 30 * DAY_IN_SECONDS ) {
$new_date = $now + wp_rand( 1, 7 ) * DAY_IN_SECONDS;
$this->set_onboarding_date( $new_date );
return;
}
// Fallback | Default case: Randomize within the range of $time_to_onboard.
$new_date = $now + wp_rand( 120, $time_to_onboard );
$this->set_onboarding_date( $new_date );
}
/**
* Sets the onboarding date.
*
* This method updates the CMPLZ_OPT_ONBOARDING_DATE option with the provided date
* and returns the updated date.
*
* @param int $date The onboarding date timestamp to be set.
* @return void
*/
private function set_onboarding_date( int $date ): void {
update_option( cmplz_wsc::WSC_OPT_ONBOARDING_DATE, $date, false );
}
/**
* Retrieves the onboarding docs (terms and conditions or newsletter policy) from the cookiedatabase endpoint.
*
* @param string $type The type of document to retrieve (wsc_terms or newsletter_terms).
* @return array An array containing the terms and conditions.
*/
private function get_onboarding_doc(string $type): array
{
$current_user_locale = get_user_locale();
$param = str_replace('_', '-', $current_user_locale);
$endpoint = $type === 'wsc_terms' ? cmplz_wsc_auth::WSC_TERMS_ENDPOINT : cmplz_wsc_auth::NEWSLETTER_TERMS_ENDPOINT;
$endpoint = base64_decode($endpoint);
$request = wp_remote_get($endpoint . '/' . $param, array(
'timeout' => 15,
'sslverify' => true,
'headers' => [
'Accept' => 'application/json',
'Content-Type' => 'application/json; charset=utf-8',
],
));
// Check for errors
if (is_wp_error($request)) {
// If there's an error, get the error message
$error_message = $request->get_error_message();
return [
'doc' => false,
'error' => $error_message
];
}
// Check for valid response code
$response_code = wp_remote_retrieve_response_code($request);
if ($response_code !== 200) {
return [
'doc' => false,
'error' => 'COMPLIANZ: error retrieving terms and conditions'
];
}
// Get the body of the response
$body = wp_remote_retrieve_body($request);
$decoded_body = json_decode($body);
if (json_last_error() !== JSON_ERROR_NONE || !isset($decoded_body->data)) {
return [
'doc' => false,
'error' => 'COMPLIANZ: error processing the response'
];
}
$output = json_decode($body)->data;
return [
'doc' => $output
];
}
/**
* Processes the plugin actions.
*
* This method processes the plugin action, such as installing or activating a plugin.
* It downloads the plugin if the action is to install the plugin, or activates the plugin if the action is to activate the plugin.
*
* @param string $action The action to be performed.
* @param array $posted_data The data associated with the action.
* @return array The updated list of recommended plugins with their status.
*/
private function process_plugin_action(string $action, array $posted_data): array
{
require_once(cmplz_path . 'class-installer.php');
$slug = $posted_data['slug'] ?? [];
$plugins = $posted_data['plugins'] ?? [];
$plugin = new cmplz_installer($slug);
if ($action === 'install_plugin') {
$plugin->download_plugin();
} elseif ($action === 'activate_plugin') {
$plugin->activate_plugin();
}
return $this->get_recommended_plugins_status($plugins);
}
/**
* Retrieves the status of the recommended plugins.
*
* This method retrieves the status of the recommended plugins, such as Complianz and its add-ons.
* It checks if the plugin is downloaded, activated, or installed, and returns the status.
*
* @param array $plugins The list of recommended plugins.
* @return array The updated list of recommended plugins with their status.
*/
public function get_recommended_plugins_status(array $plugins): array
{
require_once(cmplz_path . 'class-installer.php');
$plugins_left = 0;
foreach ($plugins as $index => $plugin) {
$slug = sanitize_title($plugin['slug']);
$premium = $plugin['premium'] ?? false;
$premium = $premium ? sanitize_title($premium) : false;
//check if plugin is downloaded
$installer = new cmplz_installer($slug);
if (!$installer->plugin_is_downloaded()) {
// check for plugins to download/install
$plugins[$index]['status'] = 'not-installed';
$plugins_left++;
} else if ($installer->plugin_is_activated()) {
$plugins[$index]['status'] = 'activated';
} else {
$plugins[$index]['status'] = 'installed';
}
//If not found, check for premium
//if free is activated, skip this step
//don't update is the premium status is not-installed. Then we leave it as it is.
if ($premium && $plugins[$index]['status'] !== 'activated') {
$installer = new cmplz_installer($premium);
if ($installer->plugin_is_activated()) {
$plugins[$index]['status'] = 'activated';
} else if ($installer->plugin_is_downloaded()) {
$plugins[$index]['status'] = 'installed';
}
}
}
if (!$plugins_left) {
$this->update_onboarding_status('plugins', true);
}
return $plugins;
}
/**
* Updates the onboarding status for a specific step.
*
* This method updates the onboarding status for the given step with the provided value.
* It retrieves the current onboarding status from the WordPress options, updates the status
* for the specified step, and saves the updated status back to the options.
* If the 'terms', 'newsletter', and 'plugins' steps are all marked as true, it sets the
* onboarding complete flag.
*
* @param string $step The step for which the onboarding status is being updated.
* @param bool $value The value to set for the specified step.
* @return void
*/
public static function update_onboarding_status(string $step, bool $value): void {
$cmplz_wsc_onboarding_status = get_option('cmplz_wsc_onboarding_status', []);
$cmplz_wsc_onboarding_status[$step] = $value;
update_option('cmplz_wsc_onboarding_status', $cmplz_wsc_onboarding_status, false);
// check the cmplz_wsc_onboarding_status array if 'terms', 'newsletter' and 'plugins' are true, set the onboarding complete flag
if ($cmplz_wsc_onboarding_status['terms'] && $cmplz_wsc_onboarding_status['newsletter'] && $cmplz_wsc_onboarding_status['plugins']) {
update_option('cmplz_wsc_onboarding_complete', true, false);
}
}
/**
* Schedule a store onboarding consent event if not already scheduled.
*
* @param string $hook The action hook name.
* @param int $delay The delay in seconds for scheduling the event.
* @param array $posted_data The arguments to pass to the event.
* @return void
*/
public static function schedule_store_onboarding_consent(string $hook, int $delay, array $posted_data): void
{
if (wp_next_scheduled($hook, $posted_data)) {
cmplz_wsc_logger::log_errors($hook, "COMPLIANZ: event '$hook' already scheduled");
return;
}
$event = wp_schedule_single_event(time() + $delay, $hook, $posted_data);
if (is_wp_error($event)) {
cmplz_wsc_logger::log_errors($hook, "COMPLIANZ: error scheduling event '$hook': " . $event->get_error_message());
}
}
/**
* Handles the wsc onboarding consent.
*
* This static method is responsible for storing the consent given by the user
* during the onboarding process for wsc.
*
* @param string $type The type of consent being stored.
* @param array $posted_data The data associated with the consent.
* @return void
*/
public static function cmplz_store_wsc_onboarding_consent_handler(string $type, array $posted_data): void
{
cmplz_wsc_auth::store_onboarding_consent($type, $posted_data);
}
/**
* Check and handle WSC consent.
*
* This static method checks if the user has executed the onboarding/authentication process.
* If the onboarding is complete but the consent is missing, it schedules an event to send the consent again.
*
* @return void
*/
public function check_wsc_consent(): void
{
$hook = 'cmplz_store_wsc_onboarding_consent';
if ($this->cmplz_retrieve_scheduled_event_by_hook($hook)) { // If the wsc consent is already scheduled, exit
return;
}
$signup_date = get_option('cmplz_wsc_signup_date');
if (!$signup_date) { // exit if the onboarding/authentication is not complete
return;
}
$consent = get_option('cmplz_consent_wsc_consent');
if ($consent) { // exit if the consent already exists
return;
}
$email_address = cmplz_get_option(cmplz_wsc::WSC_EMAIL_OPTION_KEY);
if (!is_email($email_address)) { // exit if the email is not set
return;
}
$timestamp = $signup_date * 1000; // convert seconds to milliseconds to match the javascript timestamp of the react app
$url = add_query_arg('retry', 'true', site_url()); // pass the site_url adding retry=true to identify this is a missed consent
$posted_data = [
'email' => $email_address,
'timestamp' => $timestamp,
'url' => esc_url($url),
];
// schedule a single event to send the consent after 1000 seconds
self::schedule_store_onboarding_consent($hook, 1000, ['wsc_consent', $posted_data]);
cmplz_wsc_logger::log_errors('check_wsc_consent', 'COMPLIANZ: missed wsc_consent scheduled');
}
/**
* Retrieve the already scheduled event.
*
* This method retrieves the already scheduled event from the cron array.
*
* @param string $hook The action hook name.
* @return bool Returns true if the event is already scheduled, false otherwise.
*/
public function cmplz_retrieve_scheduled_event_by_hook($hook): bool {
$cron_array = _get_cron_array();
foreach ($cron_array as $timestamp => $events) {
foreach ($events as $key => $event) {
if ($key === $hook) {
return true;
}
}
}
return false;
}
/**
* Handles the onboarding dismiss action.
*
* This method handles the onboarding dismiss action for the specified step.
* It increments the dismissed count for the specified step and updates the option accordingly.
* The method also deletes the onboarding date option to reset the onboarding process.
*
* @param string $step The step for which the onboarding dismiss action is being handled.
* @return void
*/
private function store_onboarding_dismiss( string $step ): void {
if ( ! in_array( $step, array( 'websitescan', 'newsletter', 'onboarding' ), true ) ) {
return;
}
delete_option( cmplz_wsc::WSC_OPT_ONBOARDING_DATE );
switch ( $step ) {
case 'websitescan':
$dismiss = (int) get_option( 'cmplz_wsc_websitescan_dismissed', 0 );
++$dismiss;
update_option( 'cmplz_wsc_websitescan_dismissed', $dismiss, false );
break;
case 'newsletter':
update_option( 'cmplz_wsc_newsletter_dismissed', true, false );
break;
case 'onboarding':
$dismiss = (int) get_option( 'cmplz_wsc_onboarding_dismissed', 0 );
++$dismiss;
update_option( 'cmplz_wsc_onboarding_dismissed', $dismiss, false );
break;
default:
break;
}
if ( $this->wsc_is_dismissed() ) {
COMPLIANZ::$wsc_scanner->wsc_scan_forced();
}
}
/**
* Handles the onboarding dismiss action on plugin auto-update.
*
* This method checks if the Complianz GDPR plugin is being auto-updated.
* If the plugin is found in the list of updated plugins, it calls the handle_onboarding_dismiss method.
*
* @param array $results The results of the auto-update process.
* @return void
*/
public function handle_onboarding_dismiss_on_autoupdate( array $results ): void {
if ( empty( $results['plugin'] ) || ! is_array( $results['plugin'] ) ) {
return;
}
$plugin_slug = self::CMPLZ_PLUGIN_SLUG;
foreach ( $results['plugin'] as $plugin ) {
if ( ! empty( $plugin->item->slug ) && strpos( $plugin->item->slug, $plugin_slug ) !== false ) {
$this->check_onboarding_status();
break;
}
}
}
/**
* Checks if the onboarding or websitescan has been dismissed.
*
* This method retrieves the dismissal counts for both onboarding and websitescan,
* sums them up, and returns true if the total dismissals are greater than or equal to 2.
*
* @return bool True if the total dismissals are greater than or equal to 2, false otherwise.
*/
public function wsc_is_dismissed(): bool {
$onboarding_dismissed = (int) get_option( 'cmplz_wsc_onboarding_dismissed', false );
$websitescan_dismissed = (int) get_option( 'cmplz_wsc_websitescan_dismissed', false );
$total_dismissed = $onboarding_dismissed + $websitescan_dismissed;
$is_dismissed = $total_dismissed >= self::WSC_MAX_DISMISS;
if ( $is_dismissed ) {
delete_option( cmplz_wsc::WSC_OPT_ONBOARDING_DATE );
}
return $is_dismissed;
}
/**
* Checks if the WSC (Website Scan) is locked.
*
* This method checks if the WSC is locked by verifying if the user is already authenticated.
* If the user is authenticated, it returns false indicating that the WSC is not locked.
* If the user is not authenticated, it checks if the WSC has been dismissed and returns the result.
*
* @return bool Returns true if the WSC is locked, false otherwise.
*/
public function wsc_locked(): bool {
$is_already_authenticated = cmplz_wsc_auth::wsc_is_authenticated();
if ( $is_already_authenticated ) {
return false;
}
return $this->wsc_is_dismissed();
}
/**
* Handles the onboarding dismiss action on plugin upgrade.
*
* This method checks if the Complianz GDPR plugin is being updated.
* If the plugin is found in the list of updated plugins, it calls the handle_onboarding_dismiss method.
*
* @param WP_Upgrader $upgrader The upgrader instance.
* @param array $hook_extra Additional information about the upgrade process.
* @return void
*/
public function handle_onboarding_dismiss_on_upgrade( WP_Upgrader $upgrader, array $hook_extra ): void {
$plugin_slug = self::CMPLZ_PLUGIN_SLUG;
if ( 'update' === $hook_extra['action'] && 'plugin' === $hook_extra['type'] && isset( $hook_extra['plugins'] ) ) {
foreach ( $hook_extra['plugins'] as $plugin ) {
if ( strpos( $plugin, $plugin_slug ) !== false ) {
$this->check_onboarding_status();
break;
}
}
}
}
}
}

View File

@@ -0,0 +1,596 @@
<?php
defined('ABSPATH') or die();
if (!class_exists("cmplz_wsc_settings")) {
class cmplz_wsc_settings
{
public function init_hooks()
{
add_action("cmplz_do_action", array($this, 'handle_wsc_settings_action'), 10, 3);
add_filter('cmplz_menu', array($this, 'add_website_scan_menu'));
add_filter('cmplz_fields', array($this, 'add_website_scan_fields'), 80);
add_action("cmplz_before_save_option", array($this, 'cmplz_before_save_option'), 100, 4);
add_action('cmplz_every_day_hook', array($this, 'check_failed_user_deletion'));
add_action('cmplz_store_newsletter_onboarding_consent', array($this, 'cmplz_store_newsletter_onboarding_consent_handler'), 10, 2);
}
/**
* Handles various onboarding actions.
*
* This method is responsible for handling different actions related to onboarding.
* It checks the user's capability to manage, and based on the action provided,
* performs the necessary operations such as sending authentication emails,
* resetting website scan, enabling or disabling the website scan, checking token status,
* and signing up for the newsletter.
*
* @param array $data The data associated with the action.
* @param string $action The action to be performed.
* @param WP_REST_Request $request The REST request object.
* @return array The updated data after performing the action.
*/
public function handle_wsc_settings_action(array $data, string $action, WP_REST_Request $request): array
{
if (!cmplz_user_can_manage()) {
return [];
}
switch ($action) {
case 'request_activation_email':
$stored_email = cmplz_get_option(cmplz_wsc::WSC_EMAIL_OPTION_KEY);
if (is_email($stored_email)) {
cmplz_wsc_auth::send_auth_email($stored_email);
// set an option with the signup date
update_option('cmplz_wsc_signup_date', time(), false);
}
break;
// reset Website Scan
case 'reset_wsc':
$reset = $this->cmplz_wsc_reset_websitescan(); // true false
$data = [
'result' => $reset,
'redirect' => cmplz_admin_url('#settings/settings-cd')
];
break;
// just enable the wsc, update the option 'cmplz_wsc_status'
case 'enable_wsc':
$data = $this->handle_wsc_actions('enable_wsc');
break;
// just disable the wsc, update the option 'cmplz_wsc_status'
case 'disable_wsc':
$data = $this->handle_wsc_actions('disable_wsc');
break;
// check the token status, return 'updated', 'token_status', 'wsc_status', 'wsc_signup_date'
case 'get_wsc_status':
$data = $this->handle_wsc_actions('get_wsc_status');
break;
// to be defined
case 'signup_newsletter':
$posted_data = $request->get_json_params();
$email = sanitize_email($posted_data['email']);
if (is_email($email)) {
cmplz_wsc_auth::newsletter_sign_up($email);
// newsletter_consent
cmplz_wsc_onboarding::schedule_store_onboarding_consent('cmplz_store_newsletter_onboarding_consent', 1200, ['newsletter_consent', $posted_data]);
}
break;
}
return $data;
}
/**
* Handles WSC (Website Scan) actions.
*
* This method handles actions related to enabling or disabling the WSC feature.
* It updates the WSC status option based on the provided action.
* It also retrieves the token, WSC status, and WSC signup date options.
*
* @param string $action The action to be performed (enable_wsc or disable_wsc).
* @return array An array containing the updated date, token status, WSC status, and WSC signup date.
*/
private function handle_wsc_actions(string $action): array
{
$data = [];
if (empty($action)) return $data;
if ($action === 'enable_wsc') update_option('cmplz_wsc_status', 'enabled', false);
if ($action === 'disable_wsc') update_option('cmplz_wsc_status', 'disabled', false);
$token_status = $this->get_token_status(); // could be false
$updated_wsc_status = get_option('cmplz_wsc_status'); // Website Scan status
$wsc_signup_date = get_option('cmplz_wsc_signup_date') ? get_option('cmplz_wsc_signup_date') : false;
$wsc_lock = COMPLIANZ::$wsc_onboarding->wsc_locked();
return [
'token_status' => $token_status, // token status
'wsc_status' => $updated_wsc_status,
'wsc_signup_date' => $wsc_signup_date,
'wsc_lock' => $wsc_lock,
];
}
/**
* Retrieves the token status.
*
* This method retrieves the token status by checking the value of the 'cmplz_wsc_signup_status' option.
* If the option is not set, it retrieves the token using the 'get_token' method and sets the status accordingly.
* The possible values for the status are 'pending', 'enabled', and 'disabled'.
*
* @return string The token status.
*/
public static function get_token_status(): string
{
$status = get_option('cmplz_wsc_signup_status', false);
$token = cmplz_get_transient('cmplz_wsc_access_token');
$error_token_api = get_option('cmplz_wsc_error_token_api');
if (!$token) {
$token = cmplz_wsc_auth::get_token(true);
}
if ($token) {
$status = 'enabled';
} elseif (!$token && $error_token_api) {
$status = 'error';
} else {
$status = 'disabled';
}
if ($status !== get_option('cmplz_wsc_signup_status')) {
update_option('cmplz_wsc_signup_status', $status);
}
return $status;
}
/**
* Add the website scan ux to Settings > APIs
* It modifies the existing menu array by appending a new menu item for website scan under the 'settings-cd' menu item.
*
* @param array $menu The existing menu array.
* @return array The modified menu array with the website scan menu item added.
*
*/
public function add_website_scan_menu(array $menu): array
{
foreach ($menu as $key => $item) {
if ($item['id'] === 'settings') {
foreach ($item['menu_items'] as $menu_key => $menu_item) {
if ($menu_item['id'] === 'settings-cd') {
$websiteScanItem = [
'id' => 'settings-websitescan',
'title' => __('Website Scan', 'complianz-gdpr'),
'intro' => __('Here you can manage your credentials. If you dont want to use the Website Scan, you can reset it. A token will be created to verify your website. After creating your credentials, please make sure to check your email for a confirmation.', 'complianz-gdpr'),
'premium' => false,
'upgrade' => 'https://complianz.io/pricing',
'premium_text' => __("View and manage Processing Agreements with %sComplianz GDPR Premium%s", 'complianz-gdpr'),
'helpLink' => 'https://complianz.io/about-the-website-scan/',
];
$menu[$key]['menu_items'][$menu_key]['groups'][] = $websiteScanItem;
}
}
}
}
return $menu;
}
/**
* Add Website Scan fields
*
* This method is used to add website scan fields to an array of fields.
*
* @param array $fields The array of fields to add the website scan fields to.
* @return array The updated array of fields with the website scan fields added.
*/
public function add_website_scan_fields(array $fields): array
{
return array_merge(
$fields,
[
// wsc fields
[
'id' => cmplz_wsc::WSC_EMAIL_OPTION_KEY,
'menu_id' => 'settings-cd',
'group_id' => 'settings-websitescan',
'type' => 'email',
'required' => false,
'default' => $this->retrieve_default_email_address(),
'label' => __("E-mail address", 'complianz-gdpr'),
],
[
'id' => cmplz_wsc::WSC_CLIENT_ID_OPTION_KEY,
'menu_id' => 'settings-cd',
'group_id' => 'settings-websitescan',
'type' => 'text',
'required' => false,
'default' => '',
'label' => __("Client ID", 'complianz-gdpr'),
'server_conditions' => [
'relation' => 'AND',
[
'cmplz_wsc_is_enabled()' => true,
]
],
],
[
'id' => cmplz_wsc::WSC_CLIENT_SECRET_OPTION_KEY,
'menu_id' => 'settings-cd',
'group_id' => 'settings-websitescan',
'type' => 'password',
'required' => false,
'default' => '',
'label' => __("Client Secret", 'complianz-gdpr'),
'server_conditions' => [
'relation' => 'AND',
[
'cmplz_wsc_is_enabled()' => true,
]
],
],
[
'id' => 'websitescan_status',
'menu_id' => 'settings-cd',
'group_id' => 'settings-websitescan',
'type' => 'websitescan_status',
'required' => false,
'default' => '',
],
[
'id' => 'websitescan_actions',
'menu_id' => 'settings-cd',
'group_id' => 'settings-websitescan',
'type' => 'websitescan_actions',
'required' => false,
'default' => '',
],
]
);
}
/**
* Retrieve a default email address for the onboarding dialog
*
* This method retrieves a default email address for the onboarding dialog.
* It first tries to retrieve the email address from the "cmplz wsc email" option.
* If the option is empty or not set, it falls back to the WordPress admin email address.
*
* @return string The default email address for the onboarding dialog.
*/
public function retrieve_default_email_address(): string
{
// Retrieve the email address from cmplz wsc email option
$email_address = cmplz_get_option(cmplz_wsc::WSC_EMAIL_OPTION_KEY);
// If cmplz wsc email doesn't exists, fallback to admin_email
if (empty($email_address) || $email_address === '') {
$email_address = get_bloginfo('admin_email');
}
// Return the email address if it is valid, otherwise return an empty string
return filter_var($email_address, FILTER_VALIDATE_EMAIL) ? $email_address : '';
}
/**
* This method is called before saving an option in the plugin.
*
* It performs various actions based on the field being saved, such as sending
* an authentication email if a user change the one associated to the wsc application,
* enabling/disabling the newsletter or signing up.
*
*
* @param string $field_id The ID of the field being saved.
* @param mixed $field_value The new value of the field being saved.
* @param mixed $prev_value The previous value of the field being saved.
* @return void
*/
public function cmplz_before_save_option($field_id, $field_value, $prev_value): void
{
if (!cmplz_user_can_manage()) {
return;
}
// nothing change
if ($field_value === $prev_value) {
return;
}
switch ($field_id) {
// check if the user changed the email used for the wsc activation
case cmplz_wsc::WSC_EMAIL_OPTION_KEY:
// prevent orphan site deleting the application
$this->cmplz_wsc_reset_websitescan();
// create a new application
$email = sanitize_email($field_value);
if ($email) {
cmplz_wsc_auth::send_auth_email($email);
// add an action to be executed after saving the fields
// to reset the client_id and client_secret
add_action("cmplz_after_saved_fields", array($this, 'after_saved_fields'), 100, 1);
}
break;
case 'send_notifications_email': // switch true / false
$is_enabled = $field_value;
// if ($is_enabled) {
// error_log('enable newsletter'); // wait for api
// } else {
// error_log('disable newsletter'); // wait for api
// }
break;
case 'notifications_email_address':
// newsletter signup the new address
$email = sanitize_email($field_value);
if ($email) {
cmplz_wsc_auth::newsletter_sign_up($email);
}
break;
default:
return;
}
}
/**
* This method is called after the fields are saved.
* If the email address has changed, it clears the values of 'wsc_client_id' and 'wsc_client_secret' fields.
*
* @param array $fields The array of fields.
* @return array The modified array of fields.
*/
public function after_saved_fields(array $fields): array
{
if (!cmplz_user_can_manage()) {
return $fields;
}
//in $fields, find wsc_client_id and wsc_client_secret, and set the 'value' to ''
foreach ($fields as $key => $field) {
if (in_array($field['id'], array(cmplz_wsc::WSC_CLIENT_ID_OPTION_KEY, cmplz_wsc::WSC_CLIENT_SECRET_OPTION_KEY))) {
$fields[$key]['value'] = '';
}
}
return $fields;
}
/**
*
* Handle the website scan reset
* Delete values on cmplz_settings option, options and transients.
*
*
* @return bool
*/
public function cmplz_wsc_reset_websitescan(): bool
{
global $wpdb;
$options = [
// settings
'cmplz_wsc_signup_status',
'cmplz_wsc_signup_date',
'cmplz_wsc_status',
'cmplz_wsc_onboarding_complete',
'cmplz_wsc_auth_completed',
// notices
'cmplz_wsc_error_email_mismatch',
'cmplz_wsc_error_missing_token',
'cmplz_wsc_error_email_auth_failed',
'cmplz_wsc_error_email_not_sent',
// token.
'cmplz_wsc_error_token_api',
'cmplz_wsc_connection_updated',
'cmplz_wsc_onboarding_status',
'cmplz_wsc_scan_id',
'cmplz_wsc_scan_createdAt',
'cmplz_wsc_scan_status',
'cmplz_wsc_scan_iteration',
'cmplz_wsc_scan_progress',
'cmplz_wsc_scan_first_run',
// onboarding date.
cmplz_wsc::WSC_OPT_ONBOARDING_DATE,
];
$cmplz_options = [
cmplz_wsc::WSC_EMAIL_OPTION_KEY,
cmplz_wsc::WSC_CLIENT_ID_OPTION_KEY,
cmplz_wsc::WSC_CLIENT_SECRET_OPTION_KEY
];
$cmplz_transients = [
'cmplz_wsc_access_token'
];
$dynamic_options = [
'cmplz_%_consentdata',
'cmplz_consent_error_',
'cmplz_wsc_user_deletion_%',
'cmplz_consent_%'
];
try {
$temp_credentials = get_option('cmplz_wsc_user_deletion_temp_credentials');
$client_id = cmplz_get_option(cmplz_wsc::WSC_CLIENT_ID_OPTION_KEY);
$client_secret = cmplz_get_option(cmplz_wsc::WSC_CLIENT_SECRET_OPTION_KEY);
$current_user = [
'client_id' => $client_id,
'client_secret' => $client_secret
];
$temp_credentials[] = $current_user;
update_option('cmplz_wsc_user_deletion_temp_credentials', $temp_credentials);
$token = cmplz_wsc_auth::get_token(true); // new token request, skip the one not expired stored into the db
if (!$token) {
$this->log_user_deletion_error('cmplz_wsc_user_deletion_token_error', 'Token not retrieved');
} else {
// Make the API request to delete the application
$wsc_endpoint = base64_decode(cmplz_wsc_auth::WSC_ENDPOINT);
$request = wp_remote_request($wsc_endpoint . '/api/lite/oauth_applications', array(
'method' => 'DELETE',
'headers' => array(
'Content-Type' => 'application/json',
'Authorization' => 'Bearer ' . $token,
),
'timeout' => 15,
'sslverify' => true,
));
if (is_wp_error($request)) {
$this->log_user_deletion_error('cmplz_wsc_user_deletion_error', $request->get_error_message());
}
$response_code = wp_remote_retrieve_response_code($request);
if ($response_code === 204) {
$options = array_merge($options, [
'cmplz_wsc_user_deletion_temp_credentials'
]);
} else {
$this->log_user_deletion_error('cmplz_wsc_user_deletion_error', 'Unexpected API response');
}
}
// Proceed with cleanup
foreach ($options as $option) {
delete_option($option);
}
// remove dynamic options
foreach ($dynamic_options as $option_name) {
$wpdb->query(
$wpdb->prepare(
"DELETE FROM $wpdb->options WHERE option_name LIKE %s",
$option_name
)
);
}
// remove client credentials
foreach ($cmplz_options as $cmplz_option) {
cmplz_update_option_no_hooks($cmplz_option, '');
}
foreach ($cmplz_transients as $cmplz_transient) {
cmplz_delete_transient($cmplz_transient);
}
update_option('cmplz_wsc_reset_complete', true, false);
return true;
} catch (Exception $e) {
$error = 'Exception during API request: ' . $e->getMessage();
$this->log_user_deletion_error('cmplz_wsc_user_deletion_error', $error);
if (WP_DEBUG) {
error_log($error);
}
return false;
}
}
/**
* Checks if there was an error during user deletion and triggers the reset of the website scan if necessary.
*
* This function checks if there was an error during user deletion by retrieving the values
* of the 'cmplz_wsc_user_deletion_error' and 'cmplz_wsc_user_deletion_token_error' options.
* If either of these options is set to true, the function triggers the reset of the website scan
* by calling the 'cmplz_wsc_reset_websitescan' method.
*
* @return void
*/
public function check_failed_user_deletion():void
{
$options = [
'cmplz_wsc_user_deletion_error',
'cmplz_wsc_user_deletion_error_message',
'cmplz_wsc_user_deletion_error_timestamp',
'cmplz_wsc_user_deletion_token_error',
'cmplz_wsc_user_deletion_token_error_message',
'cmplz_wsc_user_deletion_token_error_timestamp',
'cmplz_wsc_user_deletion_temp_credentials'
];
$failed_deletion = get_option('cmplz_wsc_user_deletion_temp_credentials', false); // array
if (!$failed_deletion) {
foreach ($options as $option) {
delete_option($option);
}
} else {
foreach ($failed_deletion as $client_credentials) {
if (!$client_credentials['client_id'] || !$client_credentials['client_secret']) continue;
$token = cmplz_wsc_auth::get_token(true, true, $client_credentials);
if (!$token) {
continue;
}
$wsc_endpoint = base64_decode(cmplz_wsc_auth::WSC_ENDPOINT);
$request = wp_remote_request($wsc_endpoint . '/api/lite/oauth_applications', array(
'method' => 'DELETE',
'headers' => array(
'Content-Type' => 'application/json',
'Authorization' => 'Bearer ' . $token,
),
'timeout' => 15,
'sslverify' => true,
));
$response_code = wp_remote_retrieve_response_code($request);
if ($response_code === 204) {
// update the $failed_deletions array removing the current one
$failed_deletion = array_filter($failed_deletion, function ($value) use ($client_credentials) {
return $value !== $client_credentials;
});
update_option('cmplz_wsc_user_deletion_temp_credentials', $failed_deletion);
}
}
}
}
/**
* Logs an error when a user deletion fails.
*
* @param string $option The option name to update.
* @param string $message The error message to log.
* @return void
*/
public function log_user_deletion_error(string $option, string $message): void
{
update_option($option, true, false);
update_option($option . '_message', $message, false);
update_option($option . '_timestamp', time(), false);
if (WP_DEBUG) {
error_log($message);
}
}
/**
* Handles the newsletter onboarding consent.
*
* This static method is responsible for storing the consent given by the user
* during the onboarding process for the newsletter.
*
* @param string $type The type of consent being stored.
* @param array $posted_data The data associated with the consent.
* @return void
*/
public static function cmplz_store_newsletter_onboarding_consent_handler(string $type, array $posted_data): void
{
cmplz_wsc_auth::store_onboarding_consent($type, $posted_data);
}
}
}

View File

@@ -0,0 +1,116 @@
<?php
/**
* Website Scan Integration
*/
defined('ABSPATH') or die();
if (!class_exists("cmplz_wsc")) {
class cmplz_wsc
{
private static $_this;
protected $onboarding;
protected $notices;
protected $settings;
protected $auth;
protected $logger;
// any changes on this constants should be reflected on the react application
const WSC_EMAIL_OPTION_KEY = 'cmplz_wsc_email';
const WSC_CLIENT_ID_OPTION_KEY = 'cmplz_wsc_client_id';
const WSC_CLIENT_SECRET_OPTION_KEY = 'cmplz_wsc_client_secret';
const WSC_OPT_ONBOARDING_DATE = 'cmplz_wsc_onboarding_start';
const WSC_ONBOARDING_STAGED_END = 'april 30 2025';
/**
* Class constructor for the WSC class.
*
* Initializes the WSC class and its dependencies, and runs the class.
*
*/
public function __construct()
{
if (isset(self::$_this)) {
wp_die(sprintf('%s is a singleton class and you cannot create a second instance.', get_class($this)));
}
self::$_this = $this;
$this->load_dependencies();
$this->initialize_classes();
$this->run();
}
/**
* Retrieve the instance of the class.
*
* @return object The instance of the class.
*/
public static function this()
{
return self::$_this;
}
/**
* Load the dependencies for the WSC (Website Scan) class.
*
* This method is responsible for including the necessary files and classes
* required for the proper functioning of the WSC class.
*
* @access private
* @return void
*/
private function load_dependencies()
{
require_once plugin_dir_path(__FILE__) . 'class-wsc-onboarding.php';
require_once plugin_dir_path(__FILE__) . 'class-wsc-notices.php';
require_once plugin_dir_path(__FILE__) . 'class-wsc-settings.php';
require_once plugin_dir_path(__FILE__) . 'class-wsc-auth.php';
require_once plugin_dir_path(__FILE__) . 'class-wsc-logger.php';
}
/**
* Initializes the classes required for the website scan functionality.
*
* This method creates instances of the following classes:
* - cmplz_wsc_onboarding: Handles the onboarding process for the website scan.
* - cmplz_wsc_notices: Manages the notices related to the website scan.
* - cmplz_wsc_settings: Handles the settings for the website scan.
* - cmplz_wsc_auth: Manages the authentication process for the website scan.
*
* @access private
* @return void
*/
private function initialize_classes()
{
$this->onboarding = new cmplz_wsc_onboarding();
$this->notices = new cmplz_wsc_notices();
$this->settings = new cmplz_wsc_settings();
$this->auth = new cmplz_wsc_auth();
$this->logger = new cmplz_wsc_logger();
}
/**
* Runs the necessary initialization hooks for the website scan.
*
* This method initializes the hooks for the onboarding, notices, settings, and authentication components of the website scan.
* It ensures that the necessary actions and filters are set up for these components to function properly.
*/
private function run()
{
$this->onboarding->init_hooks();
$this->notices->init_hooks();
$this->settings->init_hooks();
$this->auth->init_hooks();
$this->logger->init_hooks();
}
}
}

View File

@@ -0,0 +1,2 @@
<?php
// Silence is golden.