File: /var/www/html/wp-content/plugins/allspice/includes/settings.php
<?php
// includes/settings.php
if (!defined('ABSPATH')) exit;
define('ALLSPICE_SETTINGS_PAGE', 'allspice-settings');
define('ALLSPICE_SETTINGS_GROUP', 'allspice_settings_group');
define('ALLSPICE_SYNC_BUTTONS_SETTINGS_ACTION', 'allspice_sync_buttons_settings');
define('ALLSPICE_SYNC_RECIPES_ACTION', 'allspice_sync_recipes');
define('ALLSPICE_SYNC_ALL_ACTION', 'allspice_sync_all');
$css = '
.allspice-admin{
--asx-solid:#F9705F;
--asx-g1:#F25B57;
--asx-g2:#FF8266;
--asx-text:#303030;
--asx-text2:#606060;
--asx-text3:#B0B0B0;
--asx-bg:#FFFFFF;
--asx-bg2:#F2F2F2;
--asx-tint:#EAEAEA;
--asx-blue:#0099FF;
font-family: Inter, ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, Helvetica, Arial, "Apple Color Emoji","Segoe UI Emoji";
}
.allspice-admin .description{ color: var(--asx-text2); }
.allspice-admin__stack{
max-width: 980px;
margin: 14px 0 18px 0;
display: flex;
flex-direction: column;
gap: 14px;
}
.allspice-admin__card{
background: var(--asx-bg);
border: 1px solid rgba(194,194,194,0.38);
border-radius: 14px;
overflow: hidden;
box-shadow: 0 2px 10px rgba(0,0,0,0.06);
}
.allspice-admin__accent{
height: 6px;
background: linear-gradient(90deg, var(--asx-g1), var(--asx-g2));
}
.allspice-admin__body{ padding: 18px; }
.allspice-admin__sectionTitle{
margin: 0 0 10px 0;
color: var(--asx-text);
font-weight: 900;
font-size: 14px;
letter-spacing: 0.2px;
}
.allspice-admin__kicker{
margin: 0 0 10px 0;
color: var(--asx-text3);
font-weight: 900;
letter-spacing: 0.10em;
font-size: 11px;
}
.allspice-admin__divider{
height: 1px;
background: rgba(234,234,234,0.95);
margin: 16px 0;
}
.allspice-admin .form-table th{
color: var(--asx-text);
font-weight: 900;
padding-top: 12px;
}
.allspice-admin .form-table td{
color: var(--asx-text2);
padding-top: 12px;
}
.allspice-admin .form-table .description{
margin: 6px 0 0 0;
font-size: 12.5px;
line-height: 1.45;
}
.allspice-admin input.regular-text,
.allspice-admin input.large-text,
.allspice-admin input[type="text"],
.allspice-admin input[type="password"]{
border: 1px solid rgba(194,194,194,0.55);
border-radius: 10px;
padding: 8px 10px;
box-shadow: none;
}
.allspice-admin input:focus{
border-color: rgba(249,112,95,0.70);
box-shadow: 0 0 0 3px rgba(249,112,95,0.18);
}
.allspice-admin .button,
.allspice-admin .button-secondary,
.allspice-admin .button-primary{
border-radius: 10px !important;
font-weight: 900 !important;
}
.allspice-admin .button-primary{
background: linear-gradient(90deg, var(--asx-g1), var(--asx-g2)) !important;
border: 0 !important;
box-shadow: 0 6px 14px rgba(242,91,87,0.20) !important;
text-shadow: none !important;
}
.allspice-admin .button-primary:hover{ filter: brightness(0.98); }
.allspice-admin .button-secondary{
border-color: rgba(194,194,194,0.55) !important;
}
.allspice-admin .button:focus,
.allspice-admin .button-primary:focus,
.allspice-admin .button-secondary:focus{
box-shadow: 0 0 0 3px rgba(249,112,95,0.18) !important;
border-color: rgba(249,112,95,0.70) !important;
}
.allspice-admin__card .notice,
.allspice-admin__card .updated,
.allspice-admin__card .error,
.allspice-admin__card .wrap > .notice,
.allspice-admin__card .wrap > .updated,
.allspice-admin__card .wrap > .error{
display:none !important;
}
.allspice-mkt{ max-width: 980px; margin: 0; }
.allspice-mkt__card{
background: var(--asx-bg);
border: 1px solid rgba(194,194,194,0.38);
border-radius: 14px;
overflow: hidden;
box-shadow: 0 2px 10px rgba(0,0,0,0.06);
}
.allspice-mkt__accent{ height: 6px; background: linear-gradient(90deg, var(--asx-g1), var(--asx-g2)); }
.allspice-mkt__head{
display:flex;
align-items:center;
justify-content:space-between;
gap:14px;
padding: 14px 18px 0 18px;
}
.allspice-mkt__brand{
display:flex;
align-items:center;
gap:12px;
min-width: 0;
}
.allspice-mkt__brand img{ height: 28px; width:auto; display:block; }
.allspice-mkt__tag{
color: var(--asx-text2);
font-size: 12.5px;
line-height: 1.3;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.allspice-mkt__ctaTop{
display:flex;
gap:10px;
flex-wrap:wrap;
justify-content:flex-end;
}
.allspice-mkt__btnPrimary{
display:inline-flex;
align-items:center;
justify-content:center;
padding: 9px 12px;
border-radius: 10px;
border: 0;
text-decoration:none;
color:#fff !important;
background: linear-gradient(90deg, var(--asx-g1), var(--asx-g2));
font-weight: 900;
font-size: 13px;
box-shadow: 0 6px 14px rgba(242,91,87,0.22);
}
.allspice-mkt__btnPrimary:hover{ filter: brightness(0.98); transform: translateY(-0.5px); }
.allspice-mkt__btnSecondary{
display:inline-flex;
align-items:center;
justify-content:center;
padding: 9px 12px;
border-radius: 10px;
border: 1px solid rgba(234,234,234,0.95);
text-decoration:none;
color: var(--asx-text) !important;
background:#fff;
font-weight: 900;
font-size: 13px;
}
.allspice-mkt__btnSecondary:hover{ border-color: rgba(249,112,95,0.55); color: var(--asx-solid) !important; }
.allspice-mkt__inner{
display: grid;
grid-template-columns: 1.25fr 0.75fr;
gap: 18px;
padding: 18px;
}
@media (max-width: 900px){ .allspice-mkt__inner{ grid-template-columns: 1fr; } }
.allspice-mkt__leftTitle{
margin:0;
color: var(--asx-text3);
font-weight: 900;
letter-spacing: 0.10em;
font-size: 11px;
}
.allspice-mkt__grid{
margin-top: 10px;
display: grid;
grid-template-columns: 1fr 1fr;
gap: 12px;
}
@media (max-width: 900px){ .allspice-mkt__grid{ grid-template-columns: 1fr; } }
.allspice-mkt__feature{
background: rgba(242,242,242,0.55);
border: 1px solid rgba(234,234,234,0.95);
border-radius: 12px;
padding: 10px 12px;
}
.allspice-mkt__featureTitle{
margin:0;
color: var(--asx-text);
font-weight: 900;
font-size: 13px;
letter-spacing: 0.2px;
}
.allspice-mkt__featureBody{
margin: 4px 0 0 0;
color: var(--asx-text2);
font-size: 13px;
line-height: 1.55;
}
.allspice-mkt__right{
border-left: 1px solid rgba(234,234,234,0.9);
padding-left: 18px;
}
@media (max-width: 900px){
.allspice-mkt__right{
border-left: none;
padding-left: 0;
border-top: 1px solid rgba(234,234,234,0.9);
padding-top: 14px;
}
}
.allspice-mkt__stepsTitle{
margin:0;
color: var(--asx-text3);
font-weight: 900;
letter-spacing: 0.10em;
font-size: 11px;
}
.allspice-mkt__steps{
margin: 10px 0 0 0;
padding-left: 18px;
color: var(--asx-text2);
font-size: 13px;
line-height: 1.55;
}
.allspice-mkt__steps li{ margin: 6px 0; }
.allspice-mkt__steps strong{ color: var(--asx-text); font-weight: 900; }
.allspice-mkt__note{
margin-top: 10px;
padding: 10px 12px;
background: rgba(242,242,242,0.60);
border: 1px solid rgba(234,234,234,0.95);
border-radius: 12px;
color: var(--asx-text2);
font-size: 12.5px;
line-height: 1.5;
}
.allspice-mkt__note a{ color: var(--asx-blue); text-decoration:none; font-weight:900; }
.allspice-mkt__note a:hover{ text-decoration: underline; }
.allspice-premium-banner{
margin: 16px 0 0 0;
padding: 14px 16px;
border-radius: 14px;
border: 1px solid rgba(249,112,95,0.35);
background: rgba(249,112,95,0.08);
display:flex;
align-items:center;
justify-content:space-between;
gap:14px;
}
.allspice-premium-banner__title{
margin:0;
color: var(--asx-text);
font-weight:900;
font-size:14px;
}
.allspice-premium-banner__body{
margin:4px 0 0 0;
color: var(--asx-text2);
font-size:13px;
line-height:1.45;
max-width:700px;
}
.allspice-premium-banner__button{
display:inline-flex;
align-items:center;
justify-content:center;
white-space:nowrap;
padding:9px 12px;
border-radius:10px;
background:linear-gradient(90deg, var(--asx-g1), var(--asx-g2));
color:#fff !important;
text-decoration:none;
font-weight:900;
box-shadow:0 6px 14px rgba(242,91,87,0.18);
}
.allspice-premium-banner__button:hover{
filter:brightness(0.98);
}
@media (max-width: 700px){
.allspice-premium-banner{
align-items:flex-start;
flex-direction:column;
}
}
.allspice-sync-actions{
display:flex;
flex-wrap:wrap;
gap:10px;
align-items:center;
margin-top:12px;
}
.allspice-sync-actions form{
margin:0;
}
';
add_action('admin_enqueue_scripts', function ($hook) use ($css) {
if ($hook !== 'settings_page_' . ALLSPICE_SETTINGS_PAGE) return;
wp_register_style('allspice-admin-settings', false, [], '1.0.0');
wp_enqueue_style('allspice-admin-settings');
wp_add_inline_style('allspice-admin-settings', $css);
});
add_action('current_screen', function ($screen) {
if (!$screen || $screen->id !== 'settings_page_' . ALLSPICE_SETTINGS_PAGE) return;
remove_all_actions('admin_notices');
remove_all_actions('all_admin_notices');
remove_all_actions('network_admin_notices');
remove_all_actions('user_admin_notices');
add_action('admin_notices', function () {
$n = get_transient('allspice_admin_notice');
if (!$n || empty($n['msg'])) return;
delete_transient('allspice_admin_notice');
$type = in_array(($n['type'] ?? ''), ['success','error','warning','info'], true)
? (string)$n['type']
: 'info';
echo '<div class="notice notice-' . esc_attr($type) . ' is-dismissible">';
echo '<p>' . esc_html((string)$n['msg']) . '</p>';
echo '</div>';
}, 1);
});
function allspice_admin_card_open(string $kicker, string $title = '', bool $accent = false): void {
echo '<div class="allspice-admin__card">';
if ($accent) echo '<div class="allspice-admin__accent"></div>';
echo '<div class="allspice-admin__body">';
if ($kicker !== '') echo '<p class="allspice-admin__kicker">' . esc_html($kicker) . '</p>';
if ($title !== '') echo '<h2 class="allspice-admin__sectionTitle">' . esc_html($title) . '</h2>';
}
function allspice_admin_card_close(): void {
echo '</div></div>';
}
function allspice_render_marketing_section(array $s): void {
$portal_base = 'https://www.allspicelabs.com';
$login_url = $portal_base . '/login/';
$register_url = $portal_base . '/signup/';
$logo_url = 'https://firebasestorage.googleapis.com/v0/b/allspice-f3bfd.firebasestorage.app/o/hosted_assets%2Fallspice_combined_red_full_registered.png?alt=media';
echo '<div class="allspice-mkt"><div class="allspice-mkt__card"><div class="allspice-mkt__accent"></div>';
echo '<div class="allspice-mkt__head">';
echo '<div class="allspice-mkt__brand"><img src="' . esc_url($logo_url) . '" alt="Allspice" loading="lazy"/><div class="allspice-mkt__tag">Tools that work with your existing site</div></div>';
echo '<div class="allspice-mkt__ctaTop">';
echo '<a class="allspice-mkt__btnPrimary" href="' . esc_url($login_url) . '" target="_blank" rel="noopener noreferrer">Manage in Publisher Portal</a>';
echo '<a class="allspice-mkt__btnSecondary" href="' . esc_url($register_url) . '" target="_blank" rel="noopener noreferrer">Create account</a>';
echo '</div></div>';
echo '<div class="allspice-mkt__inner">';
echo '<div><p class="allspice-mkt__leftTitle">HOW IT WORKS</p><div class="allspice-mkt__grid">';
echo '<div class="allspice-mkt__feature"><p class="allspice-mkt__featureTitle">Save & Organize Recipes</p><p class="allspice-mkt__featureBody">Save recipes across any site in our ecosystem. The only platform that lets readers build a collection from multiple recipe sites.</p></div>';
echo '<div class="allspice-mkt__feature"><p class="allspice-mkt__featureTitle">Smart Grocery Lists</p><p class="allspice-mkt__featureBody">AI-powered grocery lists that understand ingredients, suggest substitutions, and integrate with shopping services.</p></div>';
echo '<div class="allspice-mkt__feature"><p class="allspice-mkt__featureTitle">Create Meal Plans</p><p class="allspice-mkt__featureBody">Plan entire weeks of meals from your recipes. Readers organize dinners, get suggestions, and send lists to Amazon Fresh.</p></div>';
echo '<div class="allspice-mkt__feature"><p class="allspice-mkt__featureTitle">Track Pantry</p><p class="allspice-mkt__featureBody">Check what readers already have, get substitution suggestions, and alerts for items running low or expiring soon.</p></div>';
echo '<div class="allspice-mkt__feature"><p class="allspice-mkt__featureTitle">Cook Mode</p><p class="allspice-mkt__featureBody">Step-by-step view for phone-in-hand cooking. No more scrolling between ingredients and instructions.</p></div>';
echo '<div class="allspice-mkt__feature"><p class="allspice-mkt__featureTitle">AI Chat Agent</p><p class="allspice-mkt__featureBody">Intelligent cooking assistant that helps customize recipes, troubleshoot issues, and answer questions in real-time.</p></div>';
echo '</div></div>';
echo '<div class="allspice-mkt__right"><p class="allspice-mkt__stepsTitle">SETUP</p><ol class="allspice-mkt__steps">';
echo '<li>Log in to the Publisher Portal</li>';
echo '<li>Add your site to get a <strong>Domain ID</strong></li>';
echo '<li>Copy your <strong>Publisher ID</strong> + <strong>Webhook Token</strong> into this page</li>';
echo '<li>Click <strong>Sync All</strong></li>';
echo '</ol><div class="allspice-mkt__note">Don't have an account yet? Create one at <a href="' . esc_url($register_url) . '" target="_blank" rel="noopener noreferrer">https://www.allspicelabs.com/signup/</a> to get your Publisher ID.</div></div>';
echo '</div></div></div>';
}
function allspice_render_premium_banner(array $s): void {
$premium = (bool)($s['premium'] ?? true);
if ($premium) return;
$portal_url = 'https://portal.allspicelabs.com/login/';
echo '<div class="allspice-premium-banner">';
echo '<div>';
echo '<p class="allspice-premium-banner__title">Premium subscription required</p>';
echo '<p class="allspice-premium-banner__body">This site is connected to Allspice, but features are not active for this domain until billing setup is completed in the Publisher Portal.</p>';
echo '</div>';
echo '<a class="allspice-premium-banner__button" href="' . esc_url($portal_url) . '" target="_blank" rel="noopener noreferrer">Open Publisher Portal</a>';
echo '</div>';
}
add_action('admin_menu', function () {
$hook = add_options_page(
'Allspice',
'Allspice',
'manage_options',
ALLSPICE_SETTINGS_PAGE,
'allspice_render_settings_page'
);
add_action('load-' . $hook, function () {
nocache_headers();
});
});
add_action('admin_init', function () {
register_setting(
ALLSPICE_SETTINGS_GROUP,
ALLSPICE_SETTINGS_OPTION,
['sanitize_callback' => 'allspice_sanitize_settings']
);
add_settings_section(
'allspice_main',
'',
function () {
echo '<p class="description" style="max-width:700px;">Configure your Allspice integration. These settings control how buttons are linked and refreshed from Allspice.</p>';
},
ALLSPICE_SETTINGS_PAGE
);
add_settings_field('partner_id', 'Publisher ID', 'allspice_field_partner_id', ALLSPICE_SETTINGS_PAGE, 'allspice_main');
add_settings_field('domain_id', 'Domain ID', 'allspice_field_domain_id', ALLSPICE_SETTINGS_PAGE, 'allspice_main');
add_settings_field('webhook_token', 'Webhook Token', 'allspice_field_webhook_token', ALLSPICE_SETTINGS_PAGE, 'allspice_main');
});
function allspice_sanitize_settings($input): array {
$cur = allspice_opt_get();
$in = is_array($input) ? $input : [];
$out = array_merge($cur, $in);
if (isset($in['partner_id'])) $out['partner_id'] = sanitize_text_field((string)$in['partner_id']);
if (isset($in['domain_id'])) $out['domain_id'] = sanitize_text_field((string)$in['domain_id']);
if (isset($in['webhook_token'])) $out['webhook_token'] = sanitize_text_field((string)$in['webhook_token']);
return $out;
}
function allspice_field_partner_id(): void {
$s = allspice_opt_get();
echo '<input type="text" class="regular-text" name="' . esc_attr(ALLSPICE_SETTINGS_OPTION) . '[partner_id]" value="' . esc_attr((string)$s['partner_id']) . '"/>';
echo '<p class="description">Get your <strong>Publisher ID</strong> from the <a href="' . esc_url('https://www.allspicelabs.com/login/') . '" target="_blank" rel="noopener noreferrer">Allspice Publisher Portal</a>.</p>';
}
function allspice_field_domain_id(): void {
$s = allspice_opt_get();
echo '<input type="text" class="regular-text" name="' . esc_attr(ALLSPICE_SETTINGS_OPTION) . '[domain_id]" value="' . esc_attr((string)$s['domain_id']) . '"/>';
echo '<p class="description">Identifies this WordPress site (from the Publisher Portal).</p>';
}
function allspice_field_webhook_token(): void {
$s = allspice_opt_get();
echo '<input type="password" class="regular-text" autocomplete="new-password" name="' . esc_attr(ALLSPICE_SETTINGS_OPTION) . '[webhook_token]" value="' . esc_attr((string)$s['webhook_token']) . '"/>';
echo '<p class="description">Shared secret used for secure communication with Allspice.</p>';
}
function allspice_admin_debug_url(string $path = '/'): string {
$nonce = wp_create_nonce(ALLSPICE_DEBUG_NONCE_ACTION);
$base = home_url($path);
return add_query_arg(
[
ALLSPICE_DEBUG_PARAM => '1',
ALLSPICE_DEBUG_NONCE_PARAM => $nonce,
],
$base
);
}
function allspice_render_settings_page(): void {
if (!current_user_can('manage_options')) return;
$s = allspice_opt_get();
echo '<div class="wrap allspice-admin">';
echo '<div class="allspice-admin__stack">';
allspice_render_marketing_section($s);
allspice_admin_card_open('CONFIGURATION', 'Connect WordPress to Allspice', true);
echo '<form method="post" action="options.php">';
settings_fields(ALLSPICE_SETTINGS_GROUP);
do_settings_sections(ALLSPICE_SETTINGS_PAGE);
submit_button('Save Changes');
echo '</form>';
allspice_render_premium_banner($s);
echo '<div class="allspice-admin__divider"></div>';
echo '<p class="allspice-admin__sectionTitle" style="margin-bottom:6px;">Synchronization</p>';
echo '<p class="description" style="max-width:700px;margin-top:0;">Manually sync buttons and recipes from Allspice.</p>';
echo '<div class="allspice-sync-actions">';
echo '<form method="post" action="' . esc_url(admin_url('admin-post.php')) . '">';
wp_nonce_field(ALLSPICE_SYNC_BUTTONS_SETTINGS_ACTION);
echo '<input type="hidden" name="action" value="' . esc_attr(ALLSPICE_SYNC_BUTTONS_SETTINGS_ACTION) . '"/>';
submit_button('Sync Buttons & Settings', 'secondary', 'submit', false);
echo '</form>';
echo '<form method="post" action="' . esc_url(admin_url('admin-post.php')) . '">';
wp_nonce_field(ALLSPICE_SYNC_RECIPES_ACTION);
echo '<input type="hidden" name="action" value="' . esc_attr(ALLSPICE_SYNC_RECIPES_ACTION) . '"/>';
submit_button('Sync Recipes', 'secondary', 'submit', false);
echo '</form>';
echo '<form method="post" action="' . esc_url(admin_url('admin-post.php')) . '">';
wp_nonce_field(ALLSPICE_SYNC_ALL_ACTION);
echo '<input type="hidden" name="action" value="' . esc_attr(ALLSPICE_SYNC_ALL_ACTION) . '"/>';
submit_button('Sync All', 'primary', 'submit', false);
echo '</form>';
echo '</div>';
allspice_admin_card_close();
allspice_admin_card_open('ADVANCED', 'Status & Debug', false);
$fmt = get_option('date_format') . ' ' . get_option('time_format');
echo '<table class="widefat striped" style="margin-top:6px;">';
echo '<tr><th>Linked Buttons</th><td>' . esc_html((string)($s['buttons_count'] ?? 0)) . '</td></tr>';
echo '<tr><th>Last Manual Refresh</th><td>' . esc_html(!empty($s['manual_refreshed_at']) ? wp_date($fmt, (int)$s['manual_refreshed_at']) : 'Never') . '</td></tr>';
echo '<tr><th>Last Cache Refresh</th><td>' . esc_html(!empty($s['cache_fetched_at']) ? wp_date($fmt, (int)$s['cache_fetched_at']) : 'Never') . '</td></tr>';
echo '<tr><th>Cache TTL</th><td>' . esc_html(round(((int)($s['cache_ttl'] ?? 0)) / 3600, 2)) . ' hours</td></tr>';
$recipes_count = (int)($s['recipes_count'] ?? 0);
$recipes_synced_at = (int)($s['recipes_synced_at'] ?? 0);
$recipes_last_error = (string)($s['recipes_last_error'] ?? '');
echo '<tr><th>Synced Recipes</th><td>' . esc_html((string)$recipes_count) . '</td></tr>';
echo '<tr><th>Last Recipe Sync</th><td>' . esc_html($recipes_synced_at ? wp_date($fmt, $recipes_synced_at) : 'Never') . '</td></tr>';
$tp_synced_at = (int)($s['theme_policies_synced_at'] ?? 0);
$tp_err = (string)($s['theme_policies_last_error'] ?? '');
$tp = function_exists('allspice_theme_policies_cache_get') ? allspice_theme_policies_cache_get() : ['theme' => null, 'policy' => null];
$theme_synced = ($tp_synced_at > 0) && ($tp['theme'] !== null);
$policies_synced = ($tp_synced_at > 0) && ($tp['policy'] !== null);
echo '<tr><th>Theme</th><td>' . ($theme_synced ? '<strong>Synced</strong>' : '<em>Not synced</em>') . '</td></tr>';
echo '<tr><th>Policies</th><td>' . ($policies_synced ? '<strong>Synced</strong>' : '<em>Not synced</em>') . '</td></tr>';
echo '<tr><th>Last Theme/Policies Sync</th><td>' . esc_html($tp_synced_at ? wp_date($fmt, (int)$tp_synced_at) : 'Never') . '</td></tr>';
echo '<tr><th>Manual Error</th><td>' . (!empty($s['manual_last_error']) ? esc_html($s['manual_last_error']) : '<em>None</em>') . '</td></tr>';
echo '<tr><th>Cache Error</th><td>' . (!empty($s['cache_last_error']) ? esc_html($s['cache_last_error']) : '<em>None</em>') . '</td></tr>';
echo '<tr><th>Recipe Sync Error</th><td>' . (!empty($recipes_last_error) ? esc_html($recipes_last_error) : '<em>None</em>') . '</td></tr>';
echo '<tr><th>Theme/Policies Sync Error</th><td>' . (!empty($tp_err) ? esc_html($tp_err) : '<em>None</em>') . '</td></tr>';
$premium = (bool)($s['premium'] ?? true);
$premium_checked_at = (int)($s['premium_checked_at'] ?? 0);
echo '<tr><th>Premium</th><td>' . ($premium ? '<strong>Active</strong>' : '<strong style="color:#b42318;">Not active</strong>') . '</td></tr>';
echo '<tr><th>Last Premium Check</th><td>' . esc_html($premium_checked_at ? wp_date($fmt, $premium_checked_at) : 'Never') . '</td></tr>';
echo '</table>';
echo '<div class="allspice-admin__divider"></div>';
echo '<p class="allspice-admin__sectionTitle" style="margin-bottom:6px;">Debug</p>';
echo '<p class="description" style="max-width:700px;margin-top:0;">Debug logging is restricted to administrators and requires a nonce. Use this link to enable debug mode on the front end.</p>';
$debug_url = allspice_admin_debug_url('/');
echo '<p style="margin:10px 0 8px 0;"><input type="text" class="large-text code" readonly value="' . esc_attr($debug_url) . '" /></p>';
echo '<p style="margin:0;"><a class="button button-secondary" href="' . esc_url($debug_url) . '" target="_blank" rel="noopener noreferrer">Open Debug Mode</a></p>';
allspice_admin_card_close();
echo '</div>';
echo '</div>';
}
function allspice_admin_post_sync_buttons_settings(): void {
if (!current_user_can('manage_options')) wp_die('Forbidden', 403);
check_admin_referer(ALLSPICE_SYNC_BUTTONS_SETTINGS_ACTION);
$now = time();
$rb = allspice_refresh_buttons_cache(true);
if (empty($rb['ok'])) {
allspice_opt_update(['manual_last_error' => (string)($rb['error'] ?? 'Unknown error')]);
set_transient('allspice_admin_notice', [
'msg' => 'Sync failed (buttons): ' . (string)($rb['error'] ?? 'Unknown error'),
'type' => 'error'
], 30);
wp_safe_redirect(admin_url('options-general.php?page=' . ALLSPICE_SETTINGS_PAGE));
exit;
}
$rtp = allspice_refresh_theme_policies_cache(true);
if (empty($rtp['ok'])) {
allspice_opt_update([
'manual_refreshed_at' => $now,
'manual_last_error' => '',
'theme_policies_last_error' => (string)($rtp['error'] ?? 'Unknown error'),
'theme_policies_synced_at' => $now,
]);
set_transient('allspice_admin_notice', [
'msg' => 'Buttons synced, but settings sync failed: ' . (string)($rtp['error'] ?? 'Unknown error'),
'type' => 'error'
], 30);
wp_safe_redirect(admin_url('options-general.php?page=' . ALLSPICE_SETTINGS_PAGE));
exit;
}
allspice_opt_update(['manual_refreshed_at' => $now, 'manual_last_error' => '']);
$buttons_count = (int)($rb['count'] ?? (allspice_opt_get()['buttons_count'] ?? 0));
$theme_ok = !empty($rtp['theme_ok']);
$pol_ok = !empty($rtp['policy_ok']);
set_transient('allspice_admin_notice', [
'msg' => 'Buttons & settings synced successfully. Buttons: ' . $buttons_count .
' | Theme: ' . ($theme_ok ? 'synced' : 'missing') .
' | Policies: ' . ($pol_ok ? 'synced' : 'missing'),
'type' => 'success'
], 30);
wp_safe_redirect(admin_url('options-general.php?page=' . ALLSPICE_SETTINGS_PAGE));
exit;
}
function allspice_admin_post_sync_recipes(): void {
if (!current_user_can('manage_options')) wp_die('Forbidden', 403);
check_admin_referer(ALLSPICE_SYNC_RECIPES_ACTION);
$now = time();
$rr = allspice_refresh_recipes_cache(true);
if (empty($rr['ok'])) {
allspice_opt_update([
'recipes_last_error' => (string)($rr['error'] ?? 'Unknown error'),
'recipes_synced_at' => $now,
]);
set_transient('allspice_admin_notice', [
'msg' => 'Recipe sync failed: ' . (string)($rr['error'] ?? 'Unknown error'),
'type' => 'error'
], 30);
wp_safe_redirect(admin_url('options-general.php?page=' . ALLSPICE_SETTINGS_PAGE));
exit;
}
$recipe_count = (int)($rr['count'] ?? 0);
$premium = (bool)($rr['premium'] ?? true);
set_transient('allspice_admin_notice', [
'msg' => 'Recipes synced successfully. Recipes: ' . $recipe_count .
($premium ? '' : ' | Premium is not active for this domain.'),
'type' => $premium ? 'success' : 'warning'
], 30);
wp_safe_redirect(admin_url('options-general.php?page=' . ALLSPICE_SETTINGS_PAGE));
exit;
}
function allspice_admin_post_sync_all(): void {
if (!current_user_can('manage_options')) wp_die('Forbidden', 403);
check_admin_referer(ALLSPICE_SYNC_ALL_ACTION);
$now = time();
$rb = allspice_refresh_buttons_cache(true);
if (empty($rb['ok'])) {
allspice_opt_update(['manual_last_error' => (string)($rb['error'] ?? 'Unknown error')]);
set_transient('allspice_admin_notice', [
'msg' => 'Sync failed (buttons): ' . (string)($rb['error'] ?? 'Unknown error'),
'type' => 'error'
], 30);
wp_safe_redirect(admin_url('options-general.php?page=' . ALLSPICE_SETTINGS_PAGE));
exit;
}
allspice_opt_update(['manual_refreshed_at' => $now, 'manual_last_error' => '']);
$rr = allspice_refresh_recipes_cache(true);
if (empty($rr['ok'])) {
allspice_opt_update([
'recipes_last_error' => (string)($rr['error'] ?? 'Unknown error'),
'recipes_synced_at' => $now,
]);
set_transient('allspice_admin_notice', [
'msg' => 'Buttons synced, but recipe sync failed: ' . (string)($rr['error'] ?? 'Unknown error'),
'type' => 'error'
], 30);
wp_safe_redirect(admin_url('options-general.php?page=' . ALLSPICE_SETTINGS_PAGE));
exit;
}
$rtp = allspice_refresh_theme_policies_cache(true);
if (empty($rtp['ok'])) {
allspice_opt_update([
'theme_policies_last_error' => (string)($rtp['error'] ?? 'Unknown error'),
'theme_policies_synced_at' => $now,
]);
set_transient('allspice_admin_notice', [
'msg' => 'Buttons + recipes synced, but settings sync failed: ' . (string)($rtp['error'] ?? 'Unknown error'),
'type' => 'error'
], 30);
wp_safe_redirect(admin_url('options-general.php?page=' . ALLSPICE_SETTINGS_PAGE));
exit;
}
$buttons_count = (int)($rb['count'] ?? (allspice_opt_get()['buttons_count'] ?? 0));
$recipe_count = (int)($rr['count'] ?? 0);
$premium = (bool)($rr['premium'] ?? true);
$theme_ok = !empty($rtp['theme_ok']);
$pol_ok = !empty($rtp['policy_ok']);
set_transient('allspice_admin_notice', [
'msg' => 'Synced successfully. Buttons: ' . $buttons_count .
' | Recipes: ' . $recipe_count .
' | Theme: ' . ($theme_ok ? 'synced' : 'missing') .
' | Policies: ' . ($pol_ok ? 'synced' : 'missing') .
($premium ? '' : ' | Premium is not active for this domain.'),
'type' => $premium ? 'success' : 'warning'
], 30);
wp_safe_redirect(admin_url('options-general.php?page=' . ALLSPICE_SETTINGS_PAGE));
exit;
}
add_action('admin_post_' . ALLSPICE_SYNC_BUTTONS_SETTINGS_ACTION, 'allspice_admin_post_sync_buttons_settings');
add_action('admin_post_' . ALLSPICE_SYNC_RECIPES_ACTION, 'allspice_admin_post_sync_recipes');
add_action('admin_post_' . ALLSPICE_SYNC_ALL_ACTION, 'allspice_admin_post_sync_all');