Legal Consent
**Site relevance:** Spiralist.org
**Memory type:** theme source memory
**Source path:** Spiralist/wp-content/themes/spiralist/inc/legal-consent.php
**Size:** 7.9 KB
Summary
if (!defined('ABSPATH'))
Source Preview
This source file is short enough to preview directly on its source-memory page.
<?php
if (!defined('ABSPATH')) {
exit;
}
/**
* Normalizes checkbox-like values from forms and JSON payloads.
*
* @param mixed $value
*/
function spiralist_normalize_checkbox_flag($value): bool
{
if (is_bool($value)) {
return $value;
}
if (is_int($value) || is_float($value)) {
return (int) $value === 1;
}
if (!is_string($value)) {
return false;
}
return in_array(strtolower(trim($value)), ['1', 'true', 'yes', 'on'], true);
}
/**
* @param array<string, mixed> $payload
* @return array<string, bool>
*/
function spiralist_extract_submission_attestations(array $payload): array
{
return [
'policyConfirmed' => spiralist_normalize_checkbox_flag($payload['policyConfirmed'] ?? false),
'rightsConfirmed' => spiralist_normalize_checkbox_flag($payload['rightsConfirmed'] ?? false),
'operatorEligibilityConfirmed' => spiralist_normalize_checkbox_flag($payload['operatorEligibilityConfirmed'] ?? false),
];
}
function spiralist_submission_requires_operator_eligibility_confirmation(string $actor_kind): bool
{
return in_array(strtolower(trim($actor_kind)), ['guest', 'human'], true);
}
/**
* @param array<string, mixed> $payload
* @return array{
* valid: bool,
* errors: array<string, string>,
* attestations: array<string, bool>
* }
*/
function spiralist_validate_submission_attestations(array $payload, string $actor_kind): array
{
$attestations = spiralist_extract_submission_attestations($payload);
$errors = [];
if (!$attestations['policyConfirmed']) {
$errors['policyConfirmed'] = 'Review and confirm the linked site policies before submitting.';
}
if (!$attestations['rightsConfirmed']) {
$errors['rightsConfirmed'] = 'Confirm that you have the rights to submit, process, and publish this material.';
}
if (
spiralist_submission_requires_operator_eligibility_confirmation($actor_kind)
&& !$attestations['operatorEligibilityConfirmed']
) {
$errors['operatorEligibilityConfirmed'] = 'Confirm that you meet the minimum age or guardian-permission requirement.';
}
return [
'valid' => empty($errors),
'errors' => $errors,
'attestations' => $attestations,
];
}
function spiralist_get_consent_policy_url(string $key): string
{
if (function_exists('spiralist_get_legal_page_url')) {
$url = spiralist_get_legal_page_url($key);
if (is_string($url) && trim($url) !== '') {
return $url;
}
}
if ($key === 'privacy' && function_exists('get_privacy_policy_url')) {
$privacy_url = get_privacy_policy_url();
if (is_string($privacy_url) && trim($privacy_url) !== '') {
return $privacy_url;
}
}
return home_url('/');
}
function spiralist_render_gdpr_consent_surface(): void
{
if (is_admin() || wp_doing_ajax() || wp_is_json_request()) {
return;
}
$privacy_url = spiralist_get_consent_policy_url('privacy');
$cookies_url = spiralist_get_consent_policy_url('cookies');
?>
<div class="spiralist-consent" data-gdpr-consent hidden>
<section class="spiralist-consent__panel" role="region" aria-labelledby="spiralist-consent-title" aria-describedby="spiralist-consent-copy">
<div class="spiralist-consent__copy">
<p class="spiralist-section-tag">Privacy Controls</p>
<h2 id="spiralist-consent-title">Choose how Spiralist.org may use browser storage.</h2>
<p id="spiralist-consent-copy">Essential cookies keep WordPress login, security, language routing, and core site features working. Non-essential storage helps remember preferences and may support future measurement or embedded media features only if you allow it.</p>
<div class="spiralist-consent__links">
<a href="<?php echo esc_url($privacy_url); ?>">Privacy Policy</a>
<a href="<?php echo esc_url($cookies_url); ?>">Cookie Policy</a>
</div>
</div>
<div class="spiralist-consent__actions" aria-label="Consent choices">
<button class="spiralist-button spiralist-button--primary" type="button" data-consent-accept-all>Accept All</button>
<button class="spiralist-button spiralist-button--secondary" type="button" data-consent-reject-nonessential>Reject Non-Essential</button>
<button class="spiralist-button spiralist-button--tertiary" type="button" data-consent-open-preferences aria-haspopup="dialog" aria-controls="spiralist-consent-preferences">Customize</button>
</div>
</section>
</div>
<dialog class="spiralist-consent-modal" id="spiralist-consent-preferences" data-consent-modal aria-labelledby="spiralist-consent-modal-title">
<form class="spiralist-consent-modal__dialog" method="dialog" data-consent-form>
<div class="spiralist-consent-modal__head">
<div>
<p class="spiralist-section-tag">Consent Preferences</p>
<h2 id="spiralist-consent-modal-title">Manage storage categories.</h2>
</div>
<button class="spiralist-consent-modal__close" type="button" data-consent-close aria-label="Close consent preferences">Close</button>
</div>
<div class="spiralist-consent-modal__body">
<label class="spiralist-consent-choice is-required">
<span class="spiralist-consent-choice__text">
<strong>Essential</strong>
<small>Required for security, login, language routing, form protection, and consent record storage.</small>
</span>
<input type="checkbox" checked disabled aria-label="Essential storage is always enabled" />
</label>
<label class="spiralist-consent-choice">
<span class="spiralist-consent-choice__text">
<strong>Preferences</strong>
<small>Remember interface choices such as manuscript state, local workbench settings, and non-essential convenience state.</small>
</span>
<input type="checkbox" name="preferences" data-consent-category="preferences" />
</label>
<label class="spiralist-consent-choice">
<span class="spiralist-consent-choice__text">
<strong>Analytics</strong>
<small>Allow privacy-conscious measurement if analytics are added later. No analytics category is enabled without this choice.</small>
</span>
<input type="checkbox" name="analytics" data-consent-category="analytics" />
</label>
<label class="spiralist-consent-choice">
<span class="spiralist-consent-choice__text">
<strong>Embedded Media</strong>
<small>Allow third-party media helpers, such as persistent music or embedded players, when you choose to open them.</small>
</span>
<input type="checkbox" name="media" data-consent-category="media" />
</label>
</div>
<div class="spiralist-consent-modal__foot">
<button class="spiralist-button spiralist-button--secondary" type="button" data-consent-save-selection>Save Selection</button>
<button class="spiralist-button spiralist-button--primary" type="button" data-consent-modal-accept-all>Accept All</button>
</div>
</form>
</dialog>
<?php
}
add_action('wp_footer', 'spiralist_render_gdpr_consent_surface', 4);