/
home
/
altere25
/
.trash
/
wp-to-sanity-companion.1
/
/home/altere25/.trash/wp-to-sanity-companion.1
mkdir
upload
Name
Size
Mode
Actions
assets/
-
0755
rm
includes/
-
0755
rm
templates/
-
0755
rm
assets\css\admin.css
7611
0644
edit
dl
rm
assets\js\admin.js
8534
0644
edit
dl
rm
assets\js\claude-connect.js
6502
0644
edit
dl
rm
includes\class-ad-admin.php
26374
0644
edit
dl
rm
includes\class-ad-ai-client.php
8153
0644
edit
dl
rm
includes\class-ad-auth.php
9189
0644
edit
dl
rm
includes\class-ad-cli.php
8669
0644
edit
dl
rm
includes\class-ad-extractor.php
12210
0644
edit
dl
rm
includes\class-ad-mcp.php
6429
0644
edit
dl
rm
includes\class-ad-plugin-core.php
7947
0644
edit
dl
rm
includes\class-ad-progress.php
8022
0644
edit
dl
rm
includes\class-ad-rest.php
31008
0644
edit
dl
rm
includes\class-ad-uninstall.php
1924
0644
edit
dl
rm
includes\class-ad-webhook.php
14854
0644
edit
dl
rm
templates\admin\claude-connect.php
5152
0644
edit
dl
rm
templates\admin\dashboard.php
10457
0644
edit
dl
rm
templates\admin\export.php
16570
0644
edit
dl
rm
templates\admin\log.php
10849
0644
edit
dl
rm
templates\admin\onboarding-v2.php
3827
0644
edit
dl
rm
templates\admin\onboarding.php
10714
0644
edit
dl
rm
templates\admin\progress.php
2443
0644
edit
dl
rm
templates\admin\schema-preview.php
5213
0644
edit
dl
rm
uninstall.php
365
0644
edit
dl
rm
wp-to-sanity-companion.php
4467
0644
edit
dl
rm
Edit:
/home/altere25/.trash/wp-to-sanity-companion.1/includes\class-ad-admin.php
(26374B)
<?php /** * Altered Digital Migration — Admin UI * * Menus, settings registration, meta boxes, notices, asset enqueue, and * page render dispatch. Rebranded from "WP-to-Sanity" to "Altered Digital * Migration" with the AD palette; back-compat menu slugs preserved so * existing bookmarks keep working. * * @package AlteredDigitalMigration */ if (!defined('ABSPATH')) { exit; } class AD_Admin { /** @var AD_Plugin_Core */ private $core; /** @var AD_Progress */ private $progress; public function __construct(AD_Plugin_Core $core, AD_Progress $progress) { $this->core = $core; $this->progress = $progress; } public function register_hooks(): void { add_action('admin_menu', [$this, 'add_admin_menu']); add_action('admin_init', [$this, 'register_settings']); add_action('admin_enqueue_scripts', [$this, 'enqueue_admin_assets']); add_action('add_meta_boxes', [$this, 'add_migration_meta_box']); add_action('admin_notices', [$this, 'admin_notices']); // Multisite network admin page (only renders when network-activated). add_action('network_admin_menu', [$this, 'add_network_admin_menu']); add_action('network_admin_edit_ad_network_settings', [$this, 'handle_network_settings_save']); } // ----------------------------------------------------------------- // Menus // ----------------------------------------------------------------- public function add_admin_menu(): void { add_menu_page( __('Altered Digital', 'altered-digital'), __('Altered Digital', 'altered-digital'), 'manage_options', 'wp-to-sanity', // back-compat slug [$this, 'render_dashboard_page'], 'dashicons-migrate', 80 ); // Connect FIRST (onboarding default landing). add_submenu_page( 'wp-to-sanity', __('Connect', 'altered-digital'), __('Connect', 'altered-digital'), 'manage_options', 'wp-to-sanity-connect', [$this, 'render_connect_page'] ); // v2 wizard (5-step) — new surface, same page parent. add_submenu_page( 'wp-to-sanity', __('Onboarding Wizard', 'altered-digital'), __('Onboarding Wizard', 'altered-digital'), 'manage_options', 'altered-digital-onboarding', [$this, 'render_onboarding_v2_page'] ); add_submenu_page( 'wp-to-sanity', __('Dashboard', 'altered-digital'), __('Dashboard', 'altered-digital'), 'manage_options', 'wp-to-sanity', [$this, 'render_dashboard_page'] ); add_submenu_page( 'wp-to-sanity', __('Progress', 'altered-digital'), __('Progress', 'altered-digital'), 'manage_options', 'altered-digital-progress', [$this, 'render_progress_page'] ); add_submenu_page( 'wp-to-sanity', __('Settings', 'altered-digital'), __('Settings', 'altered-digital'), 'manage_options', 'wp-to-sanity-settings', [$this, 'render_settings_page'] ); add_submenu_page( 'wp-to-sanity', __('Migration Log', 'altered-digital'), __('Migration Log', 'altered-digital'), 'manage_options', 'wp-to-sanity-log', [$this, 'render_log_page'] ); add_submenu_page( 'wp-to-sanity', __('Export', 'altered-digital'), __('Export', 'altered-digital'), 'manage_options', 'wp-to-sanity-export', [$this, 'render_export_page'] ); // Claude Connect (Phase D5) — MCP hand-off card. add_submenu_page( 'wp-to-sanity', __('Claude Connect', 'altered-digital'), __('Claude Connect', 'altered-digital'), 'manage_options', 'altered-digital-claude', [$this, 'render_claude_connect_page'] ); // Schema Preview (Phase D3) — AI-generated Sanity schema. add_submenu_page( 'wp-to-sanity', __('Schema Preview', 'altered-digital'), __('Schema Preview', 'altered-digital'), 'manage_options', 'altered-digital-schema', [$this, 'render_schema_preview_page'] ); } // ----------------------------------------------------------------- // Settings registration // ----------------------------------------------------------------- public function register_settings(): void { register_setting( 'ad_settings_group', 'ad_settings', [ 'type' => 'array', 'sanitize_callback' => [$this, 'sanitize_settings'], ] ); add_settings_section( 'ad_webhook_section', __('Webhook Configuration', 'altered-digital'), [$this, 'render_webhook_section'], 'wp-to-sanity-settings' ); add_settings_field('webhook_url', __('Webhook URL', 'altered-digital'), [$this, 'render_webhook_url_field'], 'wp-to-sanity-settings', 'ad_webhook_section'); add_settings_field('webhook_secret', __('Webhook Secret', 'altered-digital'), [$this, 'render_webhook_secret_field'], 'wp-to-sanity-settings', 'ad_webhook_section'); add_settings_field('auto_sync', __('Auto Sync', 'altered-digital'), [$this, 'render_auto_sync_field'], 'wp-to-sanity-settings', 'ad_webhook_section'); add_settings_section( 'ad_content_section', __('Content Settings', 'altered-digital'), [$this, 'render_content_section'], 'wp-to-sanity-settings' ); add_settings_field('include_drafts', __('Include Drafts', 'altered-digital'), [$this, 'render_include_drafts_field'], 'wp-to-sanity-settings', 'ad_content_section'); add_settings_field('post_types', __('Post Types', 'altered-digital'), [$this, 'render_post_types_field'], 'wp-to-sanity-settings', 'ad_content_section'); add_settings_field('taxonomies', __('Taxonomies', 'altered-digital'), [$this, 'render_taxonomies_field'], 'wp-to-sanity-settings', 'ad_content_section'); add_settings_section( 'ad_service_section', __('Altered Digital Service', 'altered-digital'), [$this, 'render_service_section'], 'wp-to-sanity-settings' ); add_settings_field('service_url', __('Service URL', 'altered-digital'), [$this, 'render_service_url_field'], 'wp-to-sanity-settings', 'ad_service_section'); add_settings_field('admin_token', __('Admin Token', 'altered-digital'), [$this, 'render_admin_token_field'], 'wp-to-sanity-settings', 'ad_service_section'); add_settings_field('tenant_id', __('Tenant ID', 'altered-digital'), [$this, 'render_tenant_id_field'], 'wp-to-sanity-settings', 'ad_service_section'); add_settings_field('ai_service_url', __('AI Service URL', 'altered-digital'), [$this, 'render_ai_service_url_field'], 'wp-to-sanity-settings', 'ad_service_section'); } public function sanitize_settings(array $input): array { $sanitized = []; $sanitized['webhook_url'] = esc_url_raw($input['webhook_url'] ?? ''); $sanitized['webhook_secret'] = sanitize_text_field($input['webhook_secret'] ?? $this->core->setting('webhook_secret', '')); $sanitized['auto_sync'] = isset($input['auto_sync']) && $input['auto_sync']; $sanitized['include_drafts'] = isset($input['include_drafts']) && $input['include_drafts']; $sanitized['batch_size'] = absint($input['batch_size'] ?? 100); $sanitized['post_types'] = array_map('sanitize_text_field', $input['post_types'] ?? ['post', 'page']); $sanitized['taxonomies'] = array_map('sanitize_text_field', $input['taxonomies'] ?? ['category', 'post_tag']); $sanitized['service_url'] = esc_url_raw($input['service_url'] ?? ''); $sanitized['ai_service_url'] = esc_url_raw($input['ai_service_url'] ?? ''); $submitted_token = $input['admin_token'] ?? ''; $sanitized['admin_token'] = !empty($submitted_token) ? sanitize_text_field($submitted_token) : $this->core->setting('admin_token', ''); $sanitized['tenant_id'] = sanitize_text_field($input['tenant_id'] ?? $this->core->setting('tenant_id', '')); $sanitized['account_email'] = sanitize_email($input['account_email'] ?? $this->core->setting('account_email', '')); // Preserve keys not exposed in the form (supabase creds, ai internal token). foreach (['supabase_url', 'supabase_anon_key', 'ai_service_internal_token'] as $k) { $sanitized[$k] = $this->core->setting($k, ''); } return $sanitized; } // ----------------------------------------------------------------- // Settings field renderers // ----------------------------------------------------------------- public function render_webhook_section(): void { echo '<p>' . esc_html__('Configure the webhook endpoint for sending content to Sanity.io', 'altered-digital') . '</p>'; } public function render_webhook_url_field(): void { $value = $this->core->setting('webhook_url', ''); echo '<input type="url" name="ad_settings[webhook_url]" value="' . esc_attr($value) . '" class="regular-text" placeholder="https://your-worker.workers.dev/webhook/wp">'; echo '<p class="description">' . esc_html__('The Cloudflare Worker webhook URL that receives content updates', 'altered-digital') . '</p>'; } public function render_webhook_secret_field(): void { $value = $this->core->setting('webhook_secret', ''); echo '<input type="text" name="ad_settings[webhook_secret]" value="' . esc_attr($value) . '" class="regular-text">'; echo '<button type="button" class="button" onclick="wpToSanityRegenerateSecret()">' . esc_html__('Regenerate', 'altered-digital') . '</button>'; echo '<p class="description">' . esc_html__('Used to sign webhook payloads for verification', 'altered-digital') . '</p>'; } public function render_auto_sync_field(): void { $checked = checked($this->core->setting('auto_sync', false), true, false); echo '<label><input type="checkbox" name="ad_settings[auto_sync]" value="1" ' . $checked . '> ' . esc_html__('Automatically sync content when posts are published or updated', 'altered-digital') . '</label>'; } public function render_content_section(): void { echo '<p>' . esc_html__('Configure which content types to migrate', 'altered-digital') . '</p>'; } public function render_include_drafts_field(): void { $checked = checked($this->core->setting('include_drafts', false), true, false); echo '<label><input type="checkbox" name="ad_settings[include_drafts]" value="1" ' . $checked . '> ' . esc_html__('Include draft posts in migration', 'altered-digital') . '</label>'; } public function render_post_types_field(): void { $post_types = get_post_types(['public' => true], 'objects'); $selected = $this->core->settings()['post_types'] ?? ['post', 'page']; foreach ($post_types as $pt) { $checked = checked(in_array($pt->name, $selected, true), true, false); echo '<label><input type="checkbox" name="ad_settings[post_types][]" value="' . esc_attr($pt->name) . '" ' . $checked . '> ' . esc_html($pt->label) . '</label><br>'; } } public function render_taxonomies_field(): void { $taxonomies = get_taxonomies(['public' => true], 'objects'); $selected = $this->core->settings()['taxonomies'] ?? ['category', 'post_tag']; foreach ($taxonomies as $tax) { $checked = checked(in_array($tax->name, $selected, true), true, false); echo '<label><input type="checkbox" name="ad_settings[taxonomies][]" value="' . esc_attr($tax->name) . '" ' . $checked . '> ' . esc_html($tax->label) . '</label><br>'; } } public function render_service_section(): void { echo '<p>' . esc_html__('Altered Digital Worker connection (auto-populated by the Connect wizard).', 'altered-digital') . '</p>'; } public function render_service_url_field(): void { $value = $this->core->setting('service_url', ''); echo '<input type="url" name="ad_settings[service_url]" value="' . esc_attr($value) . '" class="regular-text" placeholder="https://your-worker.workers.dev">'; } public function render_admin_token_field(): void { $value = $this->core->setting('admin_token', ''); echo '<input type="password" name="ad_settings[admin_token]" value="' . esc_attr($value) . '" class="regular-text" autocomplete="new-password">'; echo '<p class="description">' . esc_html__('Bearer token used for Worker admin endpoints. Saved server-side only.', 'altered-digital') . '</p>'; } public function render_tenant_id_field(): void { $value = $this->core->setting('tenant_id', ''); echo '<input type="text" name="ad_settings[tenant_id]" value="' . esc_attr($value) . '" class="regular-text" placeholder="(auto-populated on multi-tenant connect)">'; } public function render_ai_service_url_field(): void { $value = $this->core->setting('ai_service_url', ''); echo '<input type="url" name="ad_settings[ai_service_url]" value="' . esc_attr($value) . '" class="regular-text" placeholder="https://your-ai-service.vercel.app">'; echo '<p class="description">' . esc_html__('Vercel AI service URL for analysis, quotes, and checkout. Same for all customers.', 'altered-digital') . '</p>'; echo '<p class="description">' . esc_html__('Set automatically when you connect via the multi-tenant /v2/connect handshake.', 'altered-digital') . '</p>'; } // ----------------------------------------------------------------- // Assets // ----------------------------------------------------------------- public function enqueue_admin_assets(string $hook): void { if (strpos($hook, 'wp-to-sanity') === false && strpos($hook, 'altered-digital') === false) { return; } wp_enqueue_style('ad-admin', AD_PLUGIN_URL . 'assets/css/admin.css', [], AD_VERSION); wp_enqueue_script('ad-admin', AD_PLUGIN_URL . 'assets/js/admin.js', ['jquery'], AD_VERSION, true); wp_localize_script('ad-admin', 'wpToSanity', [ 'ajaxUrl' => admin_url('admin-ajax.php'), 'nonce' => wp_create_nonce('wp_to_sanity_admin'), 'restUrl' => rest_url('altered-digital/v1/'), 'restUrlV1' => rest_url('wp-to-sanity/v1/'), 'restNonce' => wp_create_nonce('wp_rest'), ]); // Claude Connect page gets its own script for the MCP config flow. if ($hook === 'altered-digital_page_altered-digital-claude' || strpos($hook, 'altered-digital-claude') !== false) { wp_enqueue_script( 'ad-claude-connect', AD_PLUGIN_URL . 'assets/js/claude-connect.js', ['jquery', 'ad-admin'], AD_VERSION, true ); } } // ----------------------------------------------------------------- // Meta box // ----------------------------------------------------------------- public function add_migration_meta_box(): void { $post_types = $this->core->settings()['post_types'] ?? ['post', 'page']; foreach ($post_types as $pt) { add_meta_box( 'altered_digital_migration', __('Altered Digital Migration', 'altered-digital'), [$this, 'render_migration_meta_box'], $pt, 'side', 'default' ); } } public function render_migration_meta_box(WP_Post $post): void { $last = $this->progress->get_local_last_sync($post->ID); echo '<div class="ad-meta-box">'; if ($last) { $status_class = $last['status'] === 'success' ? 'success' : 'error'; echo '<p><span class="status-badge ' . esc_attr($status_class) . '">' . esc_html(ucfirst($last['status'])) . '</span></p>'; echo '<p class="description">' . esc_html__('Last sync:', 'altered-digital') . ' ' . esc_html(date_i18n(get_option('date_format') . ' ' . get_option('time_format'), strtotime($last['created_at']))) . '</p>'; if (!empty($last['sanity_id'])) { echo '<p class="description">' . esc_html__('Sanity ID:', 'altered-digital') . ' <code>' . esc_html($last['sanity_id']) . '</code></p>'; } if ($last['status'] === 'failed' && !empty($last['error_message'])) { echo '<p class="error-message">' . esc_html($last['error_message']) . '</p>'; } } else { echo '<p class="description">' . esc_html__('Not yet synced', 'altered-digital') . '</p>'; } echo '<button type="button" class="button button-primary" onclick="wpToSanitySyncPost(' . esc_attr($post->ID) . ')">' . esc_html__('Sync to Sanity', 'altered-digital') . '</button>'; echo '</div>'; } // ----------------------------------------------------------------- // Notices // ----------------------------------------------------------------- public function admin_notices(): void { if (empty($this->core->setting('webhook_url', ''))) { echo '<div class="notice notice-warning is-dismissible"><p>' . esc_html__('Altered Digital: Please configure your webhook URL in the plugin settings or via the Connect wizard.', 'altered-digital') . '</p></div>'; } if (!function_exists('acf')) { echo '<div class="notice notice-info is-dismissible"><p>' . esc_html__('Altered Digital: ACF Pro is recommended for full field migration support.', 'altered-digital') . '</p></div>'; } } // ----------------------------------------------------------------- // Page renderers // ----------------------------------------------------------------- public function render_dashboard_page(): void { include AD_PLUGIN_DIR . 'templates/admin/dashboard.php'; } public function render_connect_page(): void { include AD_PLUGIN_DIR . 'templates/admin/onboarding.php'; } public function render_onboarding_v2_page(): void { include AD_PLUGIN_DIR . 'templates/admin/onboarding-v2.php'; } public function render_progress_page(): void { include AD_PLUGIN_DIR . 'templates/admin/progress.php'; } public function render_settings_page(): void { ?> <div class="wrap"> <h1><?php echo esc_html(get_admin_page_title()); ?></h1> <form action="options.php" method="post"> <?php settings_fields('ad_settings_group'); do_settings_sections('wp-to-sanity-settings'); submit_button(); ?> </form> </div> <?php } public function render_log_page(): void { global $wpdb; $table = $wpdb->prefix . 'ad_migration_log'; $paged = max(1, intval($_GET['paged'] ?? 1)); $per_page = 50; $offset = ($paged - 1) * $per_page; $logs = $wpdb->get_results($wpdb->prepare("SELECT * FROM {$table} ORDER BY created_at DESC LIMIT %d OFFSET %d", $per_page, $offset), ARRAY_A); $total = (int) $wpdb->get_var("SELECT COUNT(*) FROM {$table}"); $total_pages = (int) ceil($total / $per_page); include AD_PLUGIN_DIR . 'templates/admin/log.php'; } public function render_export_page(): void { include AD_PLUGIN_DIR . 'templates/admin/export.php'; } public function render_claude_connect_page(): void { include AD_PLUGIN_DIR . 'templates/admin/claude-connect.php'; } public function render_schema_preview_page(): void { include AD_PLUGIN_DIR . 'templates/admin/schema-preview.php'; } // ----------------------------------------------------------------- // Multisite network admin // ----------------------------------------------------------------- /** * Network admin menu — only added when the plugin is network-activated. * Lets the network admin push product-wide settings (Supabase, AI service * URL) to every subsite in one shot. Per-site overrides still win for * site-specific keys (webhook_secret, tenant_id, post_types). */ public function add_network_admin_menu(): void { if (!$this->core->is_network_activated()) { return; } add_menu_page( __('Altered Digital', 'altered-digital'), __('Altered Digital', 'altered-digital'), 'manage_network_options', 'ad-network-settings', [$this, 'render_network_settings_page'], 'dashicons-migrate', 80 ); } public function render_network_settings_page(): void { $sites = get_sites(['number' => 0]); $pushed = isset($_GET['pushed']) ? absint($_GET['pushed']) : 0; ?> <div class="wrap"> <h1><?php echo esc_html__('Altered Digital — Network Settings', 'altered-digital'); ?></h1> <p class="description"> <?php echo esc_html__('Push product-wide settings (Supabase URL, AI Service URL) to every subsite. Per-site settings (webhook secret, tenant id, post types) are preserved.', 'altered-digital'); ?> </p> <?php if ($pushed > 0): ?> <div class="notice notice-success is-dismissible"><p><?php echo esc_html(sprintf(__('Settings pushed to %d sites.', 'altered-digital'), $pushed)); ?></p></div> <?php endif; ?> <form method="post" action="edit.php?action=ad_network_settings"> <?php wp_nonce_field('ad_network_settings'); ?> <table class="form-table"> <tr> <th scope="row"><label for="supabase_url"><?php echo esc_html__('Supabase URL', 'altered-digital'); ?></label></th> <td><input type="url" name="supabase_url" id="supabase_url" value="<?php echo esc_attr($this->core->setting('supabase_url', '')); ?>" class="regular-text"></td> </tr> <tr> <th scope="row"><label for="supabase_anon_key"><?php echo esc_html__('Supabase Anon Key', 'altered-digital'); ?></label></th> <td><input type="text" name="supabase_anon_key" id="supabase_anon_key" value="<?php echo esc_attr($this->core->setting('supabase_anon_key', '')); ?>" class="regular-text"></td> </tr> <tr> <th scope="row"><label for="ai_service_url"><?php echo esc_html__('AI Service URL', 'altered-digital'); ?></label></th> <td><input type="url" name="ai_service_url" id="ai_service_url" value="<?php echo esc_attr($this->core->setting('ai_service_url', '')); ?>" class="regular-text"></td> </tr> </table> <p class="submit"><input type="submit" class="button button-primary" value="<?php echo esc_attr__('Push to all sites', 'altered-digital'); ?>"></p> </form> <h2><?php echo esc_html__('Sites', 'altered-digital'); ?></h2> <table class="widefat"> <thead><tr><th><?php echo esc_html__('Site', 'altered-digital'); ?></th><th><?php echo esc_html__('Tenant ID', 'altered-digital'); ?></th><th><?php echo esc_html__('Webhook URL', 'altered-digital'); ?></th></tr></thead> <tbody> <?php foreach ($sites as $site): ?> <?php switch_to_blog((int) $site->blog_id); $tenant = get_option('ad_settings', [])['tenant_id'] ?? ''; $wh = get_option('ad_settings', [])['webhook_url'] ?? ''; restore_current_blog(); ?> <tr> <td><?php echo esc_html($site->blogname . ' (' . $site->domain . $site->path . ')'); ?></td> <td><?php echo esc_html($tenant ?: '—'); ?></td> <td><?php echo esc_html($wh ?: '—'); ?></td> </tr> <?php endforeach; ?> </tbody> </table> </div> <?php } /** * Handle the network settings form submission. Pushes the product-wide * keys to every subsite's ad_settings option, preserving site-specific keys. */ public function handle_network_settings_save(): void { check_admin_referer('ad_network_settings'); if (!current_user_can('manage_network_options')) { wp_die(__('Insufficient permissions.', 'altered-digital')); } $push = [ 'supabase_url' => esc_url_raw($_POST['supabase_url'] ?? ''), 'supabase_anon_key' => sanitize_text_field($_POST['supabase_anon_key'] ?? ''), 'ai_service_url' => esc_url_raw($_POST['ai_service_url'] ?? ''), ]; $sites = get_sites(['fields' => 'ids', 'number' => 0]); $pushed = 0; foreach ($sites as $site_id) { switch_to_blog((int) $site_id); $existing = get_option('ad_settings', []); if (!is_array($existing)) { $existing = []; } // Merge — push keys overwrite, site-specific keys preserved. $merged = array_merge($existing, $push); update_option('ad_settings', $merged); restore_current_blog(); $pushed++; } wp_safe_redirect( add_query_arg(['page' => 'ad-network-settings', 'pushed' => $pushed], network_admin_url('admin.php')) ); exit; } }
Save
cmd:
run