diff --git a/includes/class-admin-page.php b/includes/class-admin-page.php
index 9af033b..ae1492c 100644
--- a/includes/class-admin-page.php
+++ b/includes/class-admin-page.php
@@ -9,6 +9,14 @@ if (!defined('ABSPATH')) {
class Thalim_HAL_Admin_Page {
+ use Thalim_HAL_Config_Trait;
+ use Thalim_HAL_CSV_Legacy_Trait;
+
+ // Feature flags — panneaux désactivés en prod, code conservé dans les traits.
+ // Basculer à true pour réactiver le panneau correspondant.
+ private const CONFIG_PANEL_ENABLED = false;
+ private const CSV_IMPORT_ENABLED = false;
+
private $api;
private $message = null;
private $wp_users_by_hal_id = null; // Cache: normalized_hal_id => ['id' => int, 'name' => string]
@@ -39,9 +47,13 @@ class Thalim_HAL_Admin_Page {
echo '
THALIM HAL Importer
';
$this->render_styles();
$this->render_message();
- $this->render_config();
+ if (self::CONFIG_PANEL_ENABLED) {
+ $this->render_config();
+ }
$this->render_preview();
- $this->render_csv_import();
+ if (self::CSV_IMPORT_ENABLED) {
+ $this->render_csv_import();
+ }
echo '';
}
@@ -53,11 +65,8 @@ class Thalim_HAL_Admin_Page {
}
$action = sanitize_text_field($_POST['thalim_hal_action']);
- if ($action === 'test_api') {
- $result = $this->api->test_connection();
- $this->message = is_wp_error($result)
- ? ['error', 'API Error: ' . $result->get_error_message()]
- : ['success', "Connection OK! Found {$result['total']} publications."];
+ if (self::CONFIG_PANEL_ENABLED && $action === 'test_api') {
+ $this->handle_test_api();
}
if ($action === 'refresh') {
@@ -72,10 +81,12 @@ class Thalim_HAL_Admin_Page {
$this->handle_import();
}
- if ($action === 'csv_upload') $this->handle_csv_upload();
- if ($action === 'csv_batch') $this->handle_csv_batch();
- if ($action === 'csv_cancel') $this->handle_csv_cancel();
- if ($action === 'csv_download_report') $this->handle_csv_download_report();
+ if (self::CSV_IMPORT_ENABLED) {
+ if ($action === 'csv_upload') $this->handle_csv_upload();
+ if ($action === 'csv_batch') $this->handle_csv_batch();
+ if ($action === 'csv_cancel') $this->handle_csv_cancel();
+ if ($action === 'csv_download_report') $this->handle_csv_download_report();
+ }
}
/**
@@ -165,24 +176,6 @@ class Thalim_HAL_Admin_Page {
esc_attr($this->message[0]), esc_html($this->message[1]));
}
- private function render_config() {
- ?>
-
-
-
-
Import en masse depuis CSV
-
- Uploader le couple hal-to-import.csv + hal-to-import-context.json
- (généré par php scripts/prepare-csv-context.php) pour importer les publications legacy.
- Chaque batch traite publications — cliquer plusieurs fois jusqu'à terminaison.
-
-
-
-
-
- render_csv_progress($queue); ?>
-
-
- 0 ? round(100 * $done / $total, 1) : 0;
- $report_ct = count($queue['report'] ?? []);
- ?>
-
-
File d'attente active — statut cible :
- — backdate :
-
- /
- publications traitées (%)
- — restantes
-
-
-
Dernière mise à jour :
-
-
-
-
- Erreur dernier batch :
-
-
-
-
-
- 0): ?>
-
-
-
-
-
- message = ['error', 'CSV ou fichier contexte manquant.'];
- return;
- }
-
- // Parse CSV -> list of hal_ids
- $fh = fopen($_FILES['csv_file']['tmp_name'], 'r');
- if (!$fh) { $this->message = ['error', 'Impossible de lire le CSV.']; return; }
- $header = fgetcsv($fh);
- $hal_col = array_search('hal_id', $header);
- $spip_col = array_search('spip_id', $header);
- if ($hal_col === false) {
- fclose($fh);
- $this->message = ['error', 'Header CSV : colonne hal_id manquante.'];
- return;
- }
- $hal_ids = [];
- $spip_map = []; // hal_id => spip_id
- while (($row = fgetcsv($fh)) !== false) {
- $hid = trim($row[$hal_col] ?? '');
- if ($hid === '') continue;
- $hal_ids[] = $hid;
- if ($spip_col !== false) $spip_map[$hid] = trim($row[$spip_col] ?? '');
- }
- fclose($fh);
- $hal_ids = array_values(array_unique($hal_ids));
-
- // Parse JSON context
- $ctx_raw = file_get_contents($_FILES['ctx_file']['tmp_name']);
- $ctx_data = json_decode($ctx_raw, true);
- if (!is_array($ctx_data) || !isset($ctx_data['ctx'])) {
- $this->message = ['error', 'Fichier contexte JSON invalide.'];
- return;
- }
-
- $status = ($_POST['post_status'] ?? 'publish') === 'pending' ? 'pending' : 'publish';
- $backdate = !empty($_POST['backdate_post']);
-
- $queue = [
- 'hal_ids' => $hal_ids,
- 'spip_map' => $spip_map,
- 'status' => $status,
- 'backdate' => $backdate,
- 'total' => count($hal_ids),
- 'done' => 0,
- 'spip_ctx' => $ctx_data['ctx'],
- 'wp_users_by_hal_id' => $ctx_data['wp_users_by_hal_id'] ?? [],
- 'report' => [],
- 'last_error' => '',
- 'updated_at' => current_time('mysql'),
- ];
- update_option(self::CSV_QUEUE_OPTION, $queue, false);
- $this->message = ['success', sprintf(
- 'CSV chargé : %d publications prêtes. Statut cible : %s. Cliquer "Traiter le prochain batch" pour lancer.',
- count($hal_ids), $status
- )];
- }
-
- private function handle_csv_batch(): void {
- $queue = get_option(self::CSV_QUEUE_OPTION, null);
- if (!$queue) { $this->message = ['error', 'Aucune queue active.']; return; }
-
- $batch = array_slice($queue['hal_ids'], $queue['done'], self::CSV_BATCH_SIZE);
- if (empty($batch)) {
- $this->message = ['success', 'Import terminé — tous les batches ont été traités.'];
- return;
- }
-
- $docs = $this->api->fetch_by_hal_ids($batch, self::CSV_BATCH_SIZE);
- if (is_wp_error($docs)) {
- $queue['last_error'] = $docs->get_error_message();
- $queue['updated_at'] = current_time('mysql');
- update_option(self::CSV_QUEUE_OPTION, $queue, false);
- $this->message = ['error', 'Erreur HAL API : ' . $docs->get_error_message()];
- return;
- }
-
- // Normalize wp_users_by_hal_id keys to lowercase for the importer
- $users_map = [];
- foreach ($queue['wp_users_by_hal_id'] as $hid => $u) {
- $users_map[strtolower(trim((string) $hid))] = $u;
- }
-
- $importer = new Thalim_HAL_Importer_Logic();
- $batch_imported = 0;
- $batch_skipped = 0;
- $batch_errors = 0;
-
- foreach ($batch as $hal_id) {
- $spip_id = $queue['spip_map'][$hal_id] ?? '';
- $doc = $docs[$hal_id] ?? null;
- $ctx = $queue['spip_ctx'][$hal_id] ?? [];
-
- if (!$doc) {
- $queue['report'][] = [$hal_id, $spip_id, '', 'not_found_in_hal', 'false', 'none', 'HAL API did not return this hal_id'];
- $batch_errors++;
- continue;
- }
-
- $post_id = $importer->import($doc, $users_map, $queue['status'], (bool) $queue['backdate'], $ctx);
- if (is_wp_error($post_id)) {
- $code = $post_id->get_error_code();
- $queue['report'][] = [$hal_id, $spip_id, '', $code, 'false', 'none', $post_id->get_error_message()];
- if ($code === 'exists') $batch_skipped++;
- else $batch_errors++;
- } else {
- $source = $importer->last_axes_source;
- $has_axe = $source !== 'none' ? 'true' : 'false';
- $queue['report'][] = [$hal_id, $spip_id, (string) $post_id, 'imported', $has_axe, $source, ''];
- $batch_imported++;
- }
- }
-
- $queue['done'] += count($batch);
- $queue['last_error'] = '';
- $queue['updated_at'] = current_time('mysql');
- update_option(self::CSV_QUEUE_OPTION, $queue, false);
-
- $this->message = ['success', sprintf(
- 'Batch traité : %d importé(s), %d déjà importé(s), %d erreur(s). Progression : %d / %d.',
- $batch_imported, $batch_skipped, $batch_errors,
- $queue['done'], $queue['total']
- )];
- }
-
- private function handle_csv_cancel(): void {
- delete_option(self::CSV_QUEUE_OPTION);
- $this->message = ['success', 'Queue CSV annulée.'];
- }
-
- private function handle_csv_download_report(): void {
- $queue = get_option(self::CSV_QUEUE_OPTION, null);
- if (!$queue || empty($queue['report'])) {
- $this->message = ['warning', 'Aucun rapport à télécharger.'];
- return;
- }
- $filename = 'hal-import-report-' . date('Ymd-His') . '.csv';
- header('Content-Type: text/csv; charset=utf-8');
- header('Content-Disposition: attachment; filename="' . $filename . '"');
- $out = fopen('php://output', 'w');
- fputcsv($out, ['hal_id', 'spip_id', 'post_id', 'status', 'has_axe', 'axes_source', 'error']);
- foreach ($queue['report'] as $row) fputcsv($out, $row);
- fclose($out);
- exit;
- }
-
- // ========================================================================
- // End CSV bulk import
- // ========================================================================
-
private function get_row_class($doc) {
if ($doc['is_imported']) return 'hal-status-imported';
if ($doc['has_match']) return 'hal-status-ready';
diff --git a/includes/trait-admin-page-config.php b/includes/trait-admin-page-config.php
new file mode 100644
index 0000000..d141c66
--- /dev/null
+++ b/includes/trait-admin-page-config.php
@@ -0,0 +1,39 @@
+
+
+ api->test_connection();
+ $this->message = is_wp_error($result)
+ ? ['error', 'API Error: ' . $result->get_error_message()]
+ : ['success', "Connection OK! Found {$result['total']} publications."];
+ }
+}
diff --git a/includes/trait-admin-page-csv-legacy.php b/includes/trait-admin-page-csv-legacy.php
new file mode 100644
index 0000000..b14502f
--- /dev/null
+++ b/includes/trait-admin-page-csv-legacy.php
@@ -0,0 +1,268 @@
+
+
+
Import en masse depuis CSV
+
+ Uploader le couple hal-to-import.csv + hal-to-import-context.json
+ (généré par php scripts/prepare-csv-context.php) pour importer les publications legacy.
+ Chaque batch traite publications — cliquer plusieurs fois jusqu'à terminaison.
+
+
+
+
+
+ render_csv_progress($queue); ?>
+
+
+ 0 ? round(100 * $done / $total, 1) : 0;
+ $report_ct = count($queue['report'] ?? []);
+ ?>
+
+
File d'attente active — statut cible :
+ — backdate :
+
+ /
+ publications traitées (%)
+ — restantes
+
+
+
Dernière mise à jour :
+
+
+
+
+ Erreur dernier batch :
+
+
+
+
+
+ 0): ?>
+
+
+
+
+
+ message = ['error', 'CSV ou fichier contexte manquant.'];
+ return;
+ }
+
+ // Parse CSV -> list of hal_ids
+ $fh = fopen($_FILES['csv_file']['tmp_name'], 'r');
+ if (!$fh) { $this->message = ['error', 'Impossible de lire le CSV.']; return; }
+ $header = fgetcsv($fh);
+ $hal_col = array_search('hal_id', $header);
+ $spip_col = array_search('spip_id', $header);
+ if ($hal_col === false) {
+ fclose($fh);
+ $this->message = ['error', 'Header CSV : colonne hal_id manquante.'];
+ return;
+ }
+ $hal_ids = [];
+ $spip_map = []; // hal_id => spip_id
+ while (($row = fgetcsv($fh)) !== false) {
+ $hid = trim($row[$hal_col] ?? '');
+ if ($hid === '') continue;
+ $hal_ids[] = $hid;
+ if ($spip_col !== false) $spip_map[$hid] = trim($row[$spip_col] ?? '');
+ }
+ fclose($fh);
+ $hal_ids = array_values(array_unique($hal_ids));
+
+ // Parse JSON context
+ $ctx_raw = file_get_contents($_FILES['ctx_file']['tmp_name']);
+ $ctx_data = json_decode($ctx_raw, true);
+ if (!is_array($ctx_data) || !isset($ctx_data['ctx'])) {
+ $this->message = ['error', 'Fichier contexte JSON invalide.'];
+ return;
+ }
+
+ $status = ($_POST['post_status'] ?? 'publish') === 'pending' ? 'pending' : 'publish';
+ $backdate = !empty($_POST['backdate_post']);
+
+ $queue = [
+ 'hal_ids' => $hal_ids,
+ 'spip_map' => $spip_map,
+ 'status' => $status,
+ 'backdate' => $backdate,
+ 'total' => count($hal_ids),
+ 'done' => 0,
+ 'spip_ctx' => $ctx_data['ctx'],
+ 'wp_users_by_hal_id' => $ctx_data['wp_users_by_hal_id'] ?? [],
+ 'report' => [],
+ 'last_error' => '',
+ 'updated_at' => current_time('mysql'),
+ ];
+ update_option(self::CSV_QUEUE_OPTION, $queue, false);
+ $this->message = ['success', sprintf(
+ 'CSV chargé : %d publications prêtes. Statut cible : %s. Cliquer "Traiter le prochain batch" pour lancer.',
+ count($hal_ids), $status
+ )];
+ }
+
+ private function handle_csv_batch(): void {
+ $queue = get_option(self::CSV_QUEUE_OPTION, null);
+ if (!$queue) { $this->message = ['error', 'Aucune queue active.']; return; }
+
+ $batch = array_slice($queue['hal_ids'], $queue['done'], self::CSV_BATCH_SIZE);
+ if (empty($batch)) {
+ $this->message = ['success', 'Import terminé — tous les batches ont été traités.'];
+ return;
+ }
+
+ $docs = $this->api->fetch_by_hal_ids($batch, self::CSV_BATCH_SIZE);
+ if (is_wp_error($docs)) {
+ $queue['last_error'] = $docs->get_error_message();
+ $queue['updated_at'] = current_time('mysql');
+ update_option(self::CSV_QUEUE_OPTION, $queue, false);
+ $this->message = ['error', 'Erreur HAL API : ' . $docs->get_error_message()];
+ return;
+ }
+
+ // Normalize wp_users_by_hal_id keys to lowercase for the importer
+ $users_map = [];
+ foreach ($queue['wp_users_by_hal_id'] as $hid => $u) {
+ $users_map[strtolower(trim((string) $hid))] = $u;
+ }
+
+ $importer = new Thalim_HAL_Importer_Logic();
+ $batch_imported = 0;
+ $batch_skipped = 0;
+ $batch_errors = 0;
+
+ foreach ($batch as $hal_id) {
+ $spip_id = $queue['spip_map'][$hal_id] ?? '';
+ $doc = $docs[$hal_id] ?? null;
+ $ctx = $queue['spip_ctx'][$hal_id] ?? [];
+
+ if (!$doc) {
+ $queue['report'][] = [$hal_id, $spip_id, '', 'not_found_in_hal', 'false', 'none', 'HAL API did not return this hal_id'];
+ $batch_errors++;
+ continue;
+ }
+
+ $post_id = $importer->import($doc, $users_map, $queue['status'], (bool) $queue['backdate'], $ctx);
+ if (is_wp_error($post_id)) {
+ $code = $post_id->get_error_code();
+ $queue['report'][] = [$hal_id, $spip_id, '', $code, 'false', 'none', $post_id->get_error_message()];
+ if ($code === 'exists') $batch_skipped++;
+ else $batch_errors++;
+ } else {
+ $source = $importer->last_axes_source;
+ $has_axe = $source !== 'none' ? 'true' : 'false';
+ $queue['report'][] = [$hal_id, $spip_id, (string) $post_id, 'imported', $has_axe, $source, ''];
+ $batch_imported++;
+ }
+ }
+
+ $queue['done'] += count($batch);
+ $queue['last_error'] = '';
+ $queue['updated_at'] = current_time('mysql');
+ update_option(self::CSV_QUEUE_OPTION, $queue, false);
+
+ $this->message = ['success', sprintf(
+ 'Batch traité : %d importé(s), %d déjà importé(s), %d erreur(s). Progression : %d / %d.',
+ $batch_imported, $batch_skipped, $batch_errors,
+ $queue['done'], $queue['total']
+ )];
+ }
+
+ private function handle_csv_cancel(): void {
+ delete_option(self::CSV_QUEUE_OPTION);
+ $this->message = ['success', 'Queue CSV annulée.'];
+ }
+
+ private function handle_csv_download_report(): void {
+ $queue = get_option(self::CSV_QUEUE_OPTION, null);
+ if (!$queue || empty($queue['report'])) {
+ $this->message = ['warning', 'Aucun rapport à télécharger.'];
+ return;
+ }
+ $filename = 'hal-import-report-' . date('Ymd-His') . '.csv';
+ header('Content-Type: text/csv; charset=utf-8');
+ header('Content-Disposition: attachment; filename="' . $filename . '"');
+ $out = fopen('php://output', 'w');
+ fputcsv($out, ['hal_id', 'spip_id', 'post_id', 'status', 'has_axe', 'axes_source', 'error']);
+ foreach ($queue['report'] as $row) fputcsv($out, $row);
+ fclose($out);
+ exit;
+ }
+}
diff --git a/thalim-hal-importer.php b/thalim-hal-importer.php
index d7b7613..a64c7d8 100644
--- a/thalim-hal-importer.php
+++ b/thalim-hal-importer.php
@@ -46,6 +46,9 @@ class Thalim_HAL_Importer {
private function load_dependencies() {
require_once THALIM_HAL_PLUGIN_DIR . 'includes/class-hal-api.php';
+ // Traits must be loaded before the class that `use`s them.
+ require_once THALIM_HAL_PLUGIN_DIR . 'includes/trait-admin-page-config.php';
+ require_once THALIM_HAL_PLUGIN_DIR . 'includes/trait-admin-page-csv-legacy.php';
require_once THALIM_HAL_PLUGIN_DIR . 'includes/class-admin-page.php';
require_once THALIM_HAL_PLUGIN_DIR . 'includes/class-importer.php';
}