Écritures Pods centralisées (class-pods-storage), catégories par slug et IDs Pods par nom, tests

This commit is contained in:
2026-06-10 21:30:41 +02:00
parent 20e2158612
commit c38f8b4d7e
5 changed files with 308 additions and 186 deletions

View File

@@ -9,38 +9,42 @@ if (!defined('ABSPATH')) {
class Thalim_HAL_Importer_Logic {
// HAL doc type -> WordPress category ID
private const DOC_TYPE_MAP = [
'ART' => 16, // Article
'COUV' => 16, // Chapitre -> Articles
'OUV' => 15, // Ouvrage -> Ouvrages
'COMM' => 13, // Communication -> Communications
'ISSUE' => 16, // Direction de numéro -> Articles
'PROCEEDINGS' => 15, // Direction d'ouvrage/Proceedings -> Ouvrages
'THESE' => 14, // Thèse -> Soutenances
'HDR' => 14, // HDR -> Soutenances
'SON' => 19, // Son -> Captations audio/vidéo
'VIDEO' => 19, // Vidéo -> Captations audio/vidéo
'NOTICE' => 16, // Notice/recension -> Articles
'BLOG' => 19, // Blog/tribune -> Médias
'TRAD' => 15, // Traduction -> Ouvrages (fonction auteur "Traduction")
'REPORT' => 4, // Rapport -> Publications et productions
'UNDEFINED' => 4, // Non défini -> Publications et productions
'POSTER' => 4, // Poster -> Publications et productions
'OTHER' => 4, // Autre -> Publications et productions
// HAL doc type -> slug de catégorie WP (résolu en term_id au runtime —
// les IDs auto-incrémentés ne survivent pas à une réimportation de base)
private const DOC_TYPE_SLUGS = [
'ART' => 'articles', // Article
'COUV' => 'articles', // Chapitre -> Articles
'OUV' => 'ouvrages', // Ouvrage -> Ouvrages
'COMM' => 'communications', // Communication -> Communications
'ISSUE' => 'articles', // Direction de numéro -> Articles
'PROCEEDINGS' => 'ouvrages', // Direction d'ouvrage/Proceedings -> Ouvrages
'THESE' => 'soutenances', // Thèse -> Soutenances
'HDR' => 'soutenances', // HDR -> Soutenances
'SON' => 'medias', // Son -> Médias
'VIDEO' => 'medias', // Vidéo -> Médias
'NOTICE' => 'articles', // Notice/recension -> Articles
'BLOG' => 'medias', // Blog/tribune -> Médias
'TRAD' => 'ouvrages', // Traduction -> Ouvrages (fonction auteur "Traduction")
'REPORT' => 'publications-et-productions', // Rapport -> Publications et productions
'UNDEFINED' => 'publications-et-productions', // Non défini -> Publications et productions
'POSTER' => 'publications-et-productions', // Poster -> Publications et productions
'OTHER' => 'publications-et-productions', // Autre -> Publications et productions
];
// Doc types that use date_de_debut instead of datetime
private const EVENT_DOC_TYPES = ['COMM', 'THESE', 'HDR', 'SON', 'VIDEO'];
// Pods IDs — queried from the DB, stable per installation
private const POD_ID_POST = 8;
private const FIELD_ID_CATEGORIE = 16; // "Type d'annonce" (picks from WP category)
private const FIELD_ID_MEMBRES = 178;
private const FIELD_ID_AUTRE_MBRES = 195; // autre_membres (unused in import, for reference)
private const FIELD_ID_AXES = 270; // axes_thematiques (picks from axe_thematique)
private const FIELD_ID_PROGRAMMES = 271; // programmes_de_recherche (picks from programme_de_recherche)
private const FIELD_ID_ETIQUETTES = 652; // étiquettes (picks from post_tag)
/**
* Résout un slug de catégorie en term_id (cache statique par requête).
*/
private function cat_id_by_slug(string $slug): ?int {
static $cache = [];
if (!array_key_exists($slug, $cache)) {
$term = get_term_by('slug', $slug, 'category');
$cache[$slug] = $term ? (int) $term->term_id : null;
}
return $cache[$slug];
}
/** Source of the axes applied on the last import(): 'spip' | 'coauthors' | 'owner' | 'none'. */
public $last_axes_source = 'none';
@@ -77,14 +81,19 @@ class Thalim_HAL_Importer_Logic {
* Get category ID for HAL doc type
*/
public function get_category_id($doc_type) {
return self::DOC_TYPE_MAP[$doc_type] ?? null;
$slug = self::DOC_TYPE_SLUGS[$doc_type] ?? null;
return $slug ? $this->cat_id_by_slug($slug) : null;
}
/**
* Get doc type mappings
* Get doc type mappings (doc type => category term_id)
*/
public function get_doc_type_map() {
return self::DOC_TYPE_MAP;
$map = [];
foreach (self::DOC_TYPE_SLUGS as $type => $slug) {
$map[$type] = $this->cat_id_by_slug($slug);
}
return $map;
}
/**
@@ -150,34 +159,10 @@ class Thalim_HAL_Importer_Logic {
$post_id = wp_insert_post($post_args, true);
if (is_wp_error($post_id)) return $post_id;
// --- Category — Pods triple-storage pattern ---
$cat_id = self::DOC_TYPE_MAP[$doc_type] ?? null;
// --- Category — stockage Pods centralisé (cf. class-pods-storage.php) ---
$cat_id = $this->get_category_id($doc_type);
if ($cat_id) {
global $wpdb;
// 1. Native WP category assignment
wp_set_post_categories($post_id, [$cat_id]);
// 2. Pods postmeta: single integer value
update_post_meta($post_id, 'categorie', $cat_id);
// 3. Pods _pods_ meta: serialized array of one integer
update_post_meta($post_id, '_pods_categorie', [$cat_id]);
// 4. wp_podsrel row
$wpdb->insert(
$wpdb->prefix . 'podsrel',
[
'pod_id' => self::POD_ID_POST,
'field_id' => self::FIELD_ID_CATEGORIE,
'item_id' => $post_id,
'related_pod_id' => 0,
'related_field_id'=> 0,
'related_item_id' => $cat_id,
'weight' => 0,
],
['%d', '%d', '%d', '%d', '%d', '%d', '%d']
);
Thalim_HAL_Pods_Storage::set_categorie($post_id, $cat_id);
}
// --- Core meta ---
@@ -220,41 +205,13 @@ class Thalim_HAL_Importer_Logic {
update_post_meta($post_id, 'fonction_auteur', 'Traduction // Translation');
}
// --- Keywords -> étiquettes (Pods triple-storage, picks from post_tag) ---
$hal_keywords = $hal_doc['keyword_s'] ?? [];
if (!empty($hal_keywords)) {
$matched_term_ids = $this->match_keywords_to_tags($hal_keywords);
if (!empty($matched_term_ids)) {
global $wpdb;
// 1. Native WP term relationship
wp_set_object_terms($post_id, $matched_term_ids, 'post_tag', true);
// 2. Individual postmeta rows (one per term ID)
foreach ($matched_term_ids as $tid) {
add_post_meta($post_id, 'etiquettes', (string) $tid);
}
// 3. _pods_etiquettes: serialized array of term IDs as integers
update_post_meta($post_id, '_pods_etiquettes', array_map('intval', $matched_term_ids));
// 4. wp_podsrel rows
foreach ($matched_term_ids as $weight => $tid) {
$wpdb->insert(
$wpdb->prefix . 'podsrel',
[
'pod_id' => self::POD_ID_POST,
'field_id' => self::FIELD_ID_ETIQUETTES,
'item_id' => $post_id,
'related_pod_id' => 0,
'related_field_id' => 0,
'related_item_id' => (int) $tid,
'weight' => $weight,
],
['%d', '%d', '%d', '%d', '%d', '%d', '%d']
);
}
}
// --- Keywords HAL + tags SPIP -> étiquettes (une seule écriture Pods) ---
$etiquette_ids = $this->match_keywords_to_tags($hal_doc['keyword_s'] ?? []);
if (!empty($spip_context['tags'])) {
$etiquette_ids = array_merge($etiquette_ids, array_map('intval', $spip_context['tags']));
}
if (!empty($etiquette_ids)) {
Thalim_HAL_Pods_Storage::set_relation($post_id, 'etiquettes', $etiquette_ids, 'post_tag');
}
// --- Date meta ---
@@ -303,50 +260,27 @@ class Thalim_HAL_Importer_Logic {
}
}
// --- Reference bibliographique from citationFull_s (cats 4, 15, 16) ---
// --- Reference bibliographique from citationFull_s (publications/ouvrages/articles) ---
$citation_cats = array_filter([
$this->cat_id_by_slug('publications-et-productions'),
$this->cat_id_by_slug('ouvrages'),
$this->cat_id_by_slug('articles'),
]);
$citation = $hal_doc['citationFull_s'] ?? '';
if ($citation && in_array($cat_id, [4, 15, 16])) {
if ($citation && in_array($cat_id, $citation_cats, true)) {
update_post_meta($post_id, 'reference_bibliographique', wp_kses_post($citation));
}
// --- Store matched THALIM members — Pods triple-storage pattern
// --- Store matched THALIM members ---
if (!empty($matched_user_ids)) {
global $wpdb;
// 1. Individual postmeta rows (one per user ID, as string)
foreach ($matched_user_ids as $uid) {
add_post_meta($post_id, 'membres', (string) $uid);
}
// 2. _pods_ meta: serialized PHP array of user IDs as integers
update_post_meta($post_id, '_pods_membres', array_map('intval', $matched_user_ids));
// 3. wp_podsrel rows (one per user, weight = position)
foreach ($matched_user_ids as $weight => $uid) {
$wpdb->insert(
$wpdb->prefix . 'podsrel',
[
'pod_id' => self::POD_ID_POST,
'field_id' => self::FIELD_ID_MEMBRES,
'item_id' => $post_id,
'related_pod_id' => 0,
'related_field_id'=> 0,
'related_item_id' => (int) $uid,
'weight' => $weight,
],
['%d', '%d', '%d', '%d', '%d', '%d', '%d']
);
}
Thalim_HAL_Pods_Storage::set_relation($post_id, 'membres', $matched_user_ids, null);
}
// --- Axes thématiques : cascade (SPIP direct > co-auteurs > owner) ---
$axes_resolution = $this->resolve_axes_cascade($matched_user_ids, $spip_context);
$this->last_axes_source = $axes_resolution['source'];
if (!empty($axes_resolution['term_ids'])) {
$this->set_pods_taxonomy_multi(
$post_id, 'axes_thematiques', self::FIELD_ID_AXES,
$axes_resolution['term_ids'], 'axe_thematique'
);
Thalim_HAL_Pods_Storage::set_relation($post_id, 'axes_thematiques', $axes_resolution['term_ids'], 'axe_thematique');
}
// --- Programmes de recherche : SPIP direct OR keyword matching ---
@@ -354,25 +288,7 @@ class Thalim_HAL_Importer_Logic {
? array_map('intval', $spip_context['programmes'])
: $this->match_terms_by_keywords($hal_doc['keyword_s'] ?? [], 'programme_de_recherche');
if (!empty($prog_ids)) {
$this->set_pods_taxonomy_multi(
$post_id, 'programmes_de_recherche', self::FIELD_ID_PROGRAMMES,
$prog_ids, 'programme_de_recherche'
);
}
// --- Étiquettes SPIP directes (en plus du matching HAL déjà fait plus haut) ---
if (!empty($spip_context['tags'])) {
// Merge avec les tags déjà posés par le bloc étiquettes plus haut
$existing = wp_get_object_terms($post_id, 'post_tag', ['fields' => 'ids']);
$merged = array_values(array_unique(array_merge(
is_array($existing) ? array_map('intval', $existing) : [],
array_map('intval', $spip_context['tags'])
)));
$this->set_pods_taxonomy_multi(
$post_id, 'etiquettes', self::FIELD_ID_ETIQUETTES,
array_diff($merged, is_array($existing) ? $existing : []),
'post_tag'
);
Thalim_HAL_Pods_Storage::set_relation($post_id, 'programmes_de_recherche', $prog_ids, 'programme_de_recherche');
}
// Unmatched authors as free text — remove matched names from the full list
@@ -389,11 +305,6 @@ class Thalim_HAL_Importer_Logic {
update_post_meta($post_id, 'autrepersonnes', implode(', ', array_values($unmatched)));
}
// --- Polylang: assign French language ---
if (function_exists('pll_set_post_language')) {
pll_set_post_language($post_id, 'fr');
}
return $post_id;
}
@@ -510,41 +421,4 @@ class Thalim_HAL_Importer_Logic {
return $ts ? date('Y-m-d', $ts) : '';
}
/**
* Generic Pods triple-storage writer for multi-value taxonomy fields.
* Writes to: wp_term_relationships, postmeta rows, _pods_ meta, wp_podsrel.
*/
private function set_pods_taxonomy_multi(int $post_id, string $field_name, int $field_id, array $term_ids, string $taxonomy): void {
if (empty($term_ids)) return;
global $wpdb;
$term_ids = array_values(array_unique(array_map('intval', $term_ids)));
// 1. wp_term_relationships
wp_set_object_terms($post_id, $term_ids, $taxonomy, true);
// 2. postmeta (one row per term ID, as string)
foreach ($term_ids as $tid) {
add_post_meta($post_id, $field_name, (string) $tid);
}
// 3. _pods_ meta: serialized array of ints
update_post_meta($post_id, '_pods_' . $field_name, $term_ids);
// 4. wp_podsrel rows (weight = position)
foreach ($term_ids as $weight => $tid) {
$wpdb->insert(
$wpdb->prefix . 'podsrel',
[
'pod_id' => self::POD_ID_POST,
'field_id' => $field_id,
'item_id' => $post_id,
'related_pod_id' => 0,
'related_field_id' => 0,
'related_item_id' => (int) $tid,
'weight' => $weight,
],
['%d', '%d', '%d', '%d', '%d', '%d', '%d']
);
}
}
}