fix: sección pre-footer portada + scripts importación delta marzo-mayo 2026
- fea-homepage.php: nuevo shortcode [fea_prefooter] — 3 columnas (Ediciones | Noticias de alcance | Publicidad) sobre el footer. Imagen noticias_2025.jpg apunta a wp-content/uploads/recursos/ (fix ruta Joomla rota). Columna central y vídeo de la semana son dinámicos (último post de las categorías respectivas). - scripts/import_new_k2_items.py: importa 169 K2 items nuevos (id > 17873) - scripts/fix_imported_k2_metas.py: asigna metas/cats/Polylang a esos 169 posts - scripts/import_new_cartas.py: importa 8 cartas nuevas (ew4r_content id > 9043, catid 27/40/41) y asigna _carta_id a los artículos K2 por fecha - scripts/import_new_content.py: importa 58 ítems ew4r_content no-carta (multimedia, noticias, tablón, etc.) con mapping catid→WP term Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,225 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
fix_imported_k2_metas.py
|
||||
|
||||
Asigna metas, categorías y Polylang a los posts importados por import_new_k2_items.py.
|
||||
Los posts WP ya existen (IDs 43914-44082); este script solo añade los metadatos.
|
||||
|
||||
Mapping: wp_id = k2_id + 26040
|
||||
"""
|
||||
|
||||
import json
|
||||
import subprocess
|
||||
import sys
|
||||
import re
|
||||
|
||||
# ── Config ─────────────────────────────────────────────────────────────────────
|
||||
JOOMLA_SSH_HOST = "134.0.10.170"
|
||||
JOOMLA_SSH_USER = "feadulta"
|
||||
JOOMLA_SSH_PASS = "6Rm2qOF@eundwpda"
|
||||
JOOMLA_DB_HOST = "127.0.0.1"
|
||||
JOOMLA_DB_USER = "fejoomla3"
|
||||
JOOMLA_DB_PASS = "5FF-}5^[>7^pK4W9"
|
||||
JOOMLA_DB_NAME = "fejoomla3"
|
||||
|
||||
WP_DOCKER = "wordpress-mysql"
|
||||
WP_DB_USER = "wordpress_user"
|
||||
WP_DB_PASS = "wordpress_pass"
|
||||
WP_DB_NAME = "wordpress_db"
|
||||
|
||||
LAST_K2_ID = 17873
|
||||
WP_ID_OFFSET = 26040 # wp_id = k2_id + WP_ID_OFFSET
|
||||
|
||||
CAT_FEADULTA = 71
|
||||
CAT_ARTICULOS = 1650
|
||||
CAT_EVANGELIO = 1647
|
||||
CAT_EUCARISTIA = 1648
|
||||
LANG_MAP = {1: 'es', 2: 'en', 3: 'fr', 4: 'it', 5: 'pt'}
|
||||
DOMINGO_RE = r'DOMINGO|SEMANA SANTA|SEMANA DE PASCUA|PENTECOST|NAVIDAD|EPIFAN'
|
||||
|
||||
DRY_RUN = '--dry-run' in sys.argv
|
||||
|
||||
# ── Helpers ────────────────────────────────────────────────────────────────────
|
||||
|
||||
def wp_execute(sql: str):
|
||||
if DRY_RUN:
|
||||
print(f" [DRY] {sql[:100]}")
|
||||
return
|
||||
cmd = ['docker', 'exec', WP_DOCKER,
|
||||
'mysql', '-u', WP_DB_USER, f'-p{WP_DB_PASS}', WP_DB_NAME,
|
||||
'--default-character-set=utf8mb4', '-e', sql]
|
||||
result = subprocess.run(cmd, capture_output=True, text=True)
|
||||
if result.returncode != 0:
|
||||
err = result.stderr.replace('mysql: [Warning] Using a password on the command line interface can be insecure.\n', '')
|
||||
if err.strip():
|
||||
print(f" [ERR] {err.strip()[:200]}", file=sys.stderr)
|
||||
|
||||
|
||||
def wp_mysql(query: str) -> list[dict]:
|
||||
cmd = ['docker', 'exec', WP_DOCKER,
|
||||
'mysql', '-u', WP_DB_USER, f'-p{WP_DB_PASS}', WP_DB_NAME,
|
||||
'--default-character-set=utf8mb4', '-B', '-e', query]
|
||||
result = subprocess.run(cmd, capture_output=True, text=True, encoding='utf-8')
|
||||
if result.returncode != 0:
|
||||
return []
|
||||
lines = result.stdout.strip().split('\n')
|
||||
if len(lines) < 2:
|
||||
return []
|
||||
headers = lines[0].split('\t')
|
||||
return [dict(zip(headers, line.split('\t'))) for line in lines[1:] if line]
|
||||
|
||||
|
||||
def esc(s: str) -> str:
|
||||
return s.replace('\\', '\\\\').replace("'", "\\'")
|
||||
|
||||
|
||||
def unhex(val: str) -> str:
|
||||
if not val or val == 'NULL':
|
||||
return ''
|
||||
try:
|
||||
return bytes.fromhex(val).decode('utf-8', errors='replace')
|
||||
except Exception:
|
||||
return val
|
||||
|
||||
|
||||
def parse_extra_fields(ef_json: str) -> dict:
|
||||
result = {'lang_val': None, 'has_libro': False}
|
||||
if not ef_json:
|
||||
return result
|
||||
try:
|
||||
fields = json.loads(ef_json)
|
||||
except json.JSONDecodeError:
|
||||
return result
|
||||
for f in fields:
|
||||
fid = str(f.get('id', ''))
|
||||
val = f.get('value')
|
||||
if fid == '16' and val is not None:
|
||||
try:
|
||||
result['lang_val'] = int(val)
|
||||
except (ValueError, TypeError):
|
||||
pass
|
||||
elif fid == '9':
|
||||
result['has_libro'] = True
|
||||
return result
|
||||
|
||||
|
||||
def determine_categories(ef: dict, title: str) -> list[int]:
|
||||
lang = ef.get('lang_val')
|
||||
es = (lang == 1 or lang is None)
|
||||
cats = [CAT_FEADULTA]
|
||||
if es and ef.get('has_libro'):
|
||||
cats.append(CAT_EVANGELIO)
|
||||
elif es and re.search(DOMINGO_RE, title, re.IGNORECASE):
|
||||
cats.append(CAT_EUCARISTIA)
|
||||
else:
|
||||
cats.append(CAT_ARTICULOS)
|
||||
return cats
|
||||
|
||||
|
||||
# ── Main ───────────────────────────────────────────────────────────────────────
|
||||
|
||||
def main():
|
||||
print(f"=== Fix metas/cats K2 items > {LAST_K2_ID} {'[DRY RUN]' if DRY_RUN else '[LIVE]'} ===\n")
|
||||
|
||||
# Cargar term_taxonomy_ids
|
||||
term_ids = [CAT_FEADULTA, CAT_ARTICULOS, CAT_EVANGELIO, CAT_EUCARISTIA]
|
||||
tt_ids = {}
|
||||
rows = wp_mysql(f"SELECT term_id, term_taxonomy_id FROM wp_term_taxonomy WHERE term_id IN ({','.join(map(str,term_ids))}) AND taxonomy='category'")
|
||||
for r in rows:
|
||||
tt_ids[int(r['term_id'])] = int(r['term_taxonomy_id'])
|
||||
print(f"TT IDs categorías: {tt_ids}")
|
||||
|
||||
pl_ids = {}
|
||||
rows = wp_mysql("SELECT t.slug, tt.term_taxonomy_id FROM wp_terms t JOIN wp_term_taxonomy tt ON tt.term_id=t.term_id WHERE tt.taxonomy='language' AND t.slug IN ('es','en','fr','it','pt')")
|
||||
for r in rows:
|
||||
pl_ids[r['slug']] = int(r['term_taxonomy_id'])
|
||||
print(f"Polylang TT IDs: {pl_ids}")
|
||||
|
||||
# Verificar que los WP posts existen
|
||||
rows = wp_mysql(f"SELECT COUNT(*) n FROM wp_posts WHERE ID BETWEEN {LAST_K2_ID+WP_ID_OFFSET+1} AND (SELECT MAX(ID) FROM wp_posts)")
|
||||
print(f"Posts WP a procesar (aprox): {rows[0]['n'] if rows else '?'}")
|
||||
|
||||
# Obtener K2 items desde Joomla
|
||||
print("\nObteniendo K2 items de Joomla prod...")
|
||||
query = (
|
||||
f"SELECT id, HEX(title) title, HEX(extra_fields) extra_fields "
|
||||
f"FROM ew4r_k2_items WHERE published=1 AND id > {LAST_K2_ID} ORDER BY id;"
|
||||
)
|
||||
mysql_cmd = (
|
||||
f"mysql -h {JOOMLA_DB_HOST} -u {JOOMLA_DB_USER} "
|
||||
f"-p'{JOOMLA_DB_PASS}' {JOOMLA_DB_NAME} "
|
||||
f"--default-character-set=utf8mb4 -B"
|
||||
)
|
||||
cmd = ['sshpass', '-p', JOOMLA_SSH_PASS, 'ssh', f'{JOOMLA_SSH_USER}@{JOOMLA_SSH_HOST}', mysql_cmd]
|
||||
result = subprocess.run(cmd, input=query, capture_output=True, text=True, encoding='utf-8')
|
||||
if result.returncode != 0:
|
||||
print(f"ERROR: {result.stderr[:300]}")
|
||||
sys.exit(1)
|
||||
|
||||
lines = result.stdout.strip().split('\n')
|
||||
headers = lines[0].split('\t')
|
||||
items = [dict(zip(headers, line.split('\t'))) for line in lines[1:] if line]
|
||||
print(f"Items obtenidos: {len(items)}")
|
||||
|
||||
stats = {'ok': 0, 'skip': 0}
|
||||
|
||||
for item in items:
|
||||
k2_id = int(item['id'])
|
||||
wp_id = k2_id + WP_ID_OFFSET
|
||||
title = unhex(item.get('title', ''))
|
||||
ef_raw = unhex(item.get('extra_fields', ''))
|
||||
ef = parse_extra_fields(ef_raw)
|
||||
lang = LANG_MAP.get(ef.get('lang_val'), 'es')
|
||||
cats = determine_categories(ef, title)
|
||||
|
||||
# Verificar que el WP post existe
|
||||
existing = wp_mysql(f"SELECT ID FROM wp_posts WHERE ID={wp_id} LIMIT 1")
|
||||
if not existing:
|
||||
print(f" [SKIP] WP post ID={wp_id} no encontrado (k2={k2_id})")
|
||||
stats['skip'] += 1
|
||||
continue
|
||||
|
||||
print(f" [{k2_id}→{wp_id}] {title[:45]} | lang={lang} | cats={cats}")
|
||||
|
||||
# Metas
|
||||
for meta_key, meta_val in [('_fgj2wp_old_k2_id', str(k2_id)), ('Idioma', str(ef.get('lang_val') or 1))]:
|
||||
wp_execute(
|
||||
f"INSERT IGNORE INTO wp_postmeta (post_id, meta_key, meta_value) "
|
||||
f"VALUES ({wp_id}, '{esc(meta_key)}', '{esc(meta_val)}')"
|
||||
)
|
||||
|
||||
# Categorías
|
||||
for term_id in cats:
|
||||
tt_id = tt_ids.get(term_id)
|
||||
if tt_id:
|
||||
wp_execute(
|
||||
f"INSERT IGNORE INTO wp_term_relationships (object_id, term_taxonomy_id) "
|
||||
f"VALUES ({wp_id}, {tt_id})"
|
||||
)
|
||||
|
||||
# Polylang
|
||||
pl_tt = pl_ids.get(lang)
|
||||
if pl_tt:
|
||||
wp_execute(
|
||||
f"INSERT IGNORE INTO wp_term_relationships (object_id, term_taxonomy_id) "
|
||||
f"VALUES ({wp_id}, {pl_tt})"
|
||||
)
|
||||
|
||||
stats['ok'] += 1
|
||||
|
||||
# Actualizar counts
|
||||
if not DRY_RUN and stats['ok'] > 0:
|
||||
print("\nActualizando counts de categorías y Polylang...")
|
||||
all_tt = list(tt_ids.values()) + list(pl_ids.values())
|
||||
tt_str = ','.join(str(x) for x in all_tt)
|
||||
wp_execute(
|
||||
f"UPDATE wp_term_taxonomy tt SET count = ("
|
||||
f"SELECT COUNT(*) FROM wp_term_relationships tr WHERE tr.term_taxonomy_id=tt.term_taxonomy_id"
|
||||
f") WHERE tt.term_taxonomy_id IN ({tt_str})"
|
||||
)
|
||||
|
||||
print(f"\n=== Resultado: {stats['ok']} ok, {stats['skip']} skip ===")
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
@@ -0,0 +1,302 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
import_new_cartas.py
|
||||
|
||||
Importa las cartas de la semana nuevas de ew4r_content (Joomla prod, id > 9043)
|
||||
al WordPress local (Docker), y luego asigna _carta_id a los artículos K2
|
||||
correspondientes según la fecha (extra_field id 15).
|
||||
|
||||
Categorías WP según catid Joomla:
|
||||
catid 27 (Carta de la semana) → WP: 6 + 21 + 71
|
||||
catid 40 (Cartas de otras sem) → WP: 21 + 71
|
||||
catid 41 (Carta semana pasada) → WP: 21 + 22 + 71
|
||||
"""
|
||||
|
||||
import json
|
||||
import subprocess
|
||||
import sys
|
||||
import re
|
||||
from datetime import datetime
|
||||
|
||||
JOOMLA_SSH_HOST = "134.0.10.170"
|
||||
JOOMLA_SSH_USER = "feadulta"
|
||||
JOOMLA_SSH_PASS = "6Rm2qOF@eundwpda"
|
||||
JOOMLA_DB_HOST = "127.0.0.1"
|
||||
JOOMLA_DB_USER = "fejoomla3"
|
||||
JOOMLA_DB_PASS = "5FF-}5^[>7^pK4W9"
|
||||
JOOMLA_DB_NAME = "fejoomla3"
|
||||
|
||||
WP_DOCKER = "wordpress-mysql"
|
||||
WP_DB_USER = "wordpress_user"
|
||||
WP_DB_PASS = "wordpress_pass"
|
||||
WP_DB_NAME = "wordpress_db"
|
||||
|
||||
LAST_CONTENT_ID = 9043 # último ew4r_content.id ya en WP
|
||||
|
||||
# WP term_ids y sus term_taxonomy_ids (se cargan dinámicamente)
|
||||
CAT_FEADULTA = 71
|
||||
CAT_CARTA_SEMANA = 6
|
||||
CAT_CARTAS_OTRAS = 21
|
||||
CAT_CARTA_PASADA = 22
|
||||
|
||||
CATID_TO_WP = {
|
||||
27: [CAT_CARTA_SEMANA, CAT_CARTAS_OTRAS, CAT_FEADULTA],
|
||||
40: [CAT_CARTAS_OTRAS, CAT_FEADULTA],
|
||||
41: [CAT_CARTAS_OTRAS, CAT_CARTA_PASADA, CAT_FEADULTA],
|
||||
}
|
||||
|
||||
DRY_RUN = '--dry-run' in sys.argv
|
||||
|
||||
# ── Helpers ────────────────────────────────────────────────────────────────────
|
||||
|
||||
def joomla_query(query: str) -> list[dict]:
|
||||
mysql_cmd = (f"mysql -h {JOOMLA_DB_HOST} -u {JOOMLA_DB_USER} "
|
||||
f"-p'{JOOMLA_DB_PASS}' {JOOMLA_DB_NAME} "
|
||||
f"--default-character-set=utf8mb4 -B")
|
||||
cmd = ['sshpass', '-p', JOOMLA_SSH_PASS,
|
||||
'ssh', f'{JOOMLA_SSH_USER}@{JOOMLA_SSH_HOST}', mysql_cmd]
|
||||
result = subprocess.run(cmd, input=query, capture_output=True,
|
||||
text=True, encoding='utf-8')
|
||||
if result.returncode != 0:
|
||||
print(f"[ERR SSH] {result.stderr[:300]}", file=sys.stderr)
|
||||
return []
|
||||
lines = result.stdout.strip().split('\n')
|
||||
if len(lines) < 2:
|
||||
return []
|
||||
headers = lines[0].split('\t')
|
||||
return [dict(zip(headers, line.split('\t'))) for line in lines[1:] if line]
|
||||
|
||||
|
||||
def wp_mysql(query: str) -> list[dict]:
|
||||
cmd = ['docker', 'exec', WP_DOCKER,
|
||||
'mysql', '-u', WP_DB_USER, f'-p{WP_DB_PASS}', WP_DB_NAME,
|
||||
'--default-character-set=utf8mb4', '-B', '-e', query]
|
||||
result = subprocess.run(cmd, capture_output=True, text=True, encoding='utf-8')
|
||||
if result.returncode != 0:
|
||||
return []
|
||||
lines = result.stdout.strip().split('\n')
|
||||
if len(lines) < 2:
|
||||
return []
|
||||
headers = lines[0].split('\t')
|
||||
return [dict(zip(headers, line.split('\t'))) for line in lines[1:] if line]
|
||||
|
||||
|
||||
def wp_execute(sql: str):
|
||||
if DRY_RUN:
|
||||
print(f" [DRY] {sql[:110]}")
|
||||
return None
|
||||
cmd = ['docker', 'exec', WP_DOCKER,
|
||||
'mysql', '-u', WP_DB_USER, f'-p{WP_DB_PASS}', WP_DB_NAME,
|
||||
'--default-character-set=utf8mb4', '-e', sql]
|
||||
result = subprocess.run(cmd, capture_output=True, text=True)
|
||||
if result.returncode != 0:
|
||||
err = result.stderr.replace('mysql: [Warning] Using a password on the command line interface can be insecure.\n', '')
|
||||
if err.strip():
|
||||
print(f" [ERR] {err.strip()[:200]}", file=sys.stderr)
|
||||
|
||||
|
||||
def esc(s: str) -> str:
|
||||
return s.replace('\\', '\\\\').replace("'", "\\'")
|
||||
|
||||
|
||||
def unhex(val: str) -> str:
|
||||
if not val or val == 'NULL':
|
||||
return ''
|
||||
try:
|
||||
return bytes.fromhex(val).decode('utf-8', errors='replace')
|
||||
except Exception:
|
||||
return val
|
||||
|
||||
|
||||
# ── Main ───────────────────────────────────────────────────────────────────────
|
||||
|
||||
def main():
|
||||
print(f"=== Import nuevas cartas (ew4r_content id > {LAST_CONTENT_ID}) "
|
||||
f"{'[DRY RUN]' if DRY_RUN else '[LIVE]'} ===\n")
|
||||
|
||||
# Cargar term_taxonomy_ids
|
||||
all_term_ids = [CAT_FEADULTA, CAT_CARTA_SEMANA, CAT_CARTAS_OTRAS, CAT_CARTA_PASADA]
|
||||
rows = wp_mysql(
|
||||
f"SELECT term_id, term_taxonomy_id FROM wp_term_taxonomy "
|
||||
f"WHERE term_id IN ({','.join(map(str,all_term_ids))}) AND taxonomy='category'"
|
||||
)
|
||||
tt_ids = {int(r['term_id']): int(r['term_taxonomy_id']) for r in rows}
|
||||
print(f"TT IDs: {tt_ids}")
|
||||
|
||||
# Cargar Polylang ES
|
||||
pl_rows = wp_mysql(
|
||||
"SELECT tt.term_taxonomy_id FROM wp_terms t "
|
||||
"JOIN wp_term_taxonomy tt ON tt.term_id=t.term_id "
|
||||
"WHERE tt.taxonomy='language' AND t.slug='es' LIMIT 1"
|
||||
)
|
||||
pl_es_tt = int(pl_rows[0]['term_taxonomy_id']) if pl_rows else None
|
||||
print(f"Polylang ES tt_id: {pl_es_tt}")
|
||||
|
||||
# Cargar user map
|
||||
user_rows = wp_mysql(
|
||||
"SELECT um.meta_value jid, u.ID wid FROM wp_users u "
|
||||
"JOIN wp_usermeta um ON um.user_id=u.ID "
|
||||
"WHERE um.meta_key='_fgj2wp_old_user_id'"
|
||||
)
|
||||
user_map = {}
|
||||
for r in user_rows:
|
||||
try:
|
||||
user_map[int(r['jid'])] = int(r['wid'])
|
||||
except ValueError:
|
||||
pass
|
||||
|
||||
# Obtener cartas nuevas de Joomla (con HEX para texto)
|
||||
print("\nObteniendo cartas nuevas de Joomla...")
|
||||
query = (
|
||||
f"SELECT id, HEX(title) title, HEX(alias) alias, "
|
||||
f"HEX(introtext) introtext, HEX(`fulltext`) fulltext_col, "
|
||||
f"catid, created, created_by "
|
||||
f"FROM ew4r_content "
|
||||
f"WHERE state=1 AND id > {LAST_CONTENT_ID} AND catid IN (27,40,41) "
|
||||
f"ORDER BY id;"
|
||||
)
|
||||
items = joomla_query(query)
|
||||
print(f"Cartas a importar: {len(items)}")
|
||||
|
||||
# Mapa fecha_carta → wp_id (para asignar _carta_id a artículos K2)
|
||||
fecha_a_wp_carta = {}
|
||||
|
||||
for item in items:
|
||||
joomla_id = int(item['id'])
|
||||
catid = int(item['catid'])
|
||||
title = unhex(item.get('title',''))
|
||||
alias = unhex(item.get('alias',''))
|
||||
intro = unhex(item.get('introtext',''))
|
||||
full = unhex(item.get('fulltext_col',''))
|
||||
created = item.get('created','') or datetime.now().strftime('%Y-%m-%d %H:%M:%S')
|
||||
created_by = int(item.get('created_by', 0) or 0)
|
||||
|
||||
content = intro + ('\n<!--more-->\n' + full if full.strip() else '')
|
||||
wp_author = user_map.get(created_by, 1)
|
||||
wp_cats = CATID_TO_WP.get(catid, [CAT_CARTAS_OTRAS, CAT_FEADULTA])
|
||||
fecha_carta = created[:10] # YYYY-MM-DD
|
||||
|
||||
print(f"\n [{joomla_id}] {title[:55]} | catid={catid} | fecha={fecha_carta}")
|
||||
print(f" → WP cats: {wp_cats}")
|
||||
|
||||
# INSERT post
|
||||
post_slug = esc(alias[:200])
|
||||
post_title = esc(title)
|
||||
post_content = esc(content)
|
||||
|
||||
wp_execute(
|
||||
f"INSERT INTO wp_posts "
|
||||
f"(post_author, post_date, post_date_gmt, post_content, post_title, "
|
||||
f"post_excerpt, post_status, comment_status, ping_status, post_name, "
|
||||
f"post_type, post_modified, post_modified_gmt, comment_count, "
|
||||
f"to_ping, pinged, post_content_filtered) VALUES ("
|
||||
f"{wp_author}, '{created}', '{created}', '{post_content}', "
|
||||
f"'{post_title}', '', 'publish', 'open', 'open', '{post_slug}', "
|
||||
f"'post', '{created}', '{created}', 0, '', '', '')"
|
||||
)
|
||||
|
||||
if DRY_RUN:
|
||||
fecha_a_wp_carta[fecha_carta] = f"DRY_WP_ID_for_{joomla_id}"
|
||||
continue
|
||||
|
||||
new_id_rows = wp_mysql("SELECT MAX(ID) new_id FROM wp_posts")
|
||||
if not new_id_rows:
|
||||
print(f" [ERR] No se pudo obtener ID del post", file=sys.stderr)
|
||||
continue
|
||||
new_wp_id = int(new_id_rows[0]['new_id'])
|
||||
print(f" → WP post ID={new_wp_id}")
|
||||
|
||||
fecha_a_wp_carta[fecha_carta] = new_wp_id
|
||||
|
||||
# Metas
|
||||
wp_execute(f"INSERT INTO wp_postmeta (post_id, meta_key, meta_value) VALUES ({new_wp_id}, '_fgj2wp_old_content_id', '{joomla_id}')")
|
||||
wp_execute(f"INSERT INTO wp_postmeta (post_id, meta_key, meta_value) VALUES ({new_wp_id}, 'Idioma', '1')")
|
||||
|
||||
# Categorías
|
||||
for term_id in wp_cats:
|
||||
tt_id = tt_ids.get(term_id)
|
||||
if tt_id:
|
||||
wp_execute(
|
||||
f"INSERT IGNORE INTO wp_term_relationships (object_id, term_taxonomy_id) "
|
||||
f"VALUES ({new_wp_id}, {tt_id})"
|
||||
)
|
||||
|
||||
# Polylang ES
|
||||
if pl_es_tt:
|
||||
wp_execute(
|
||||
f"INSERT IGNORE INTO wp_term_relationships (object_id, term_taxonomy_id) "
|
||||
f"VALUES ({new_wp_id}, {pl_es_tt})"
|
||||
)
|
||||
|
||||
print(f"\nFecha→WP carta map: {fecha_a_wp_carta}")
|
||||
|
||||
# ── Asignar _carta_id a los artículos K2 importados ──────────────────────
|
||||
if DRY_RUN or not fecha_a_wp_carta:
|
||||
print("\n[SKIP] Asignación _carta_id (dry-run o sin cartas importadas)")
|
||||
return
|
||||
|
||||
print("\n=== Asignando _carta_id a artículos K2 ===")
|
||||
|
||||
# Obtener los artículos K2 nuevos con su fecha (id 15)
|
||||
k2_query = (
|
||||
f"SELECT id, HEX(extra_fields) ef "
|
||||
f"FROM ew4r_k2_items WHERE published=1 AND id > 17873 ORDER BY id;"
|
||||
)
|
||||
k2_items = joomla_query(k2_query)
|
||||
print(f"Artículos K2 a procesar: {len(k2_items)}")
|
||||
|
||||
assigned = 0
|
||||
for k2item in k2_items:
|
||||
k2_id = int(k2item['id'])
|
||||
wp_id = k2_id + 26040 # offset conocido
|
||||
ef_raw = unhex(k2item.get('ef',''))
|
||||
|
||||
# Parsear fecha (id 15)
|
||||
fecha_art = None
|
||||
try:
|
||||
fields = json.loads(ef_raw)
|
||||
for f in fields:
|
||||
if str(f.get('id','')) == '15':
|
||||
fecha_art = str(f.get('value',''))[:10]
|
||||
break
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
if not fecha_art:
|
||||
continue
|
||||
|
||||
carta_wp_id = fecha_a_wp_carta.get(fecha_art)
|
||||
if not carta_wp_id:
|
||||
continue
|
||||
|
||||
# Verificar que el meta no existe ya
|
||||
existing = wp_mysql(
|
||||
f"SELECT meta_id FROM wp_postmeta WHERE post_id={wp_id} AND meta_key='_carta_id' LIMIT 1"
|
||||
)
|
||||
if existing:
|
||||
continue
|
||||
|
||||
wp_execute(
|
||||
f"INSERT INTO wp_postmeta (post_id, meta_key, meta_value) "
|
||||
f"VALUES ({wp_id}, '_carta_id', '{carta_wp_id}')"
|
||||
)
|
||||
print(f" K2 {k2_id} (WP {wp_id}) → _carta_id={carta_wp_id} [{fecha_art}]")
|
||||
assigned += 1
|
||||
|
||||
print(f"\n_carta_id asignado a {assigned} artículos.")
|
||||
|
||||
# Actualizar counts de categorías
|
||||
print("\nActualizando counts de categorías...")
|
||||
tt_str = ','.join(str(v) for v in tt_ids.values())
|
||||
wp_execute(
|
||||
f"UPDATE wp_term_taxonomy tt SET count = ("
|
||||
f"SELECT COUNT(*) FROM wp_term_relationships tr "
|
||||
f"WHERE tr.term_taxonomy_id=tt.term_taxonomy_id"
|
||||
f") WHERE tt.term_taxonomy_id IN ({tt_str})"
|
||||
)
|
||||
|
||||
print("\nListo.")
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
@@ -0,0 +1,249 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
import_new_content.py
|
||||
|
||||
Importa los ew4r_content items no-carta nuevos (id > 9043, catid NOT IN 27,40,41)
|
||||
al WordPress local (Docker).
|
||||
|
||||
Mapping catid → WP term_ids:
|
||||
54 (Índice multimedia) → 26
|
||||
77 (Videos) → 58
|
||||
64 (Noticias de alcance) → 41
|
||||
52 (Tablón de anuncios) → 1 (uncategorized / sin categoría)
|
||||
63 (Fechas) → 40
|
||||
61 (Lista completa de autores) → 38
|
||||
65 (Cantoral Salomé Arricibita) → 31
|
||||
otro → 1 (uncategorized)
|
||||
"""
|
||||
|
||||
import subprocess
|
||||
import sys
|
||||
from datetime import datetime
|
||||
|
||||
JOOMLA_SSH_HOST = "134.0.10.170"
|
||||
JOOMLA_SSH_USER = "feadulta"
|
||||
JOOMLA_SSH_PASS = "6Rm2qOF@eundwpda"
|
||||
JOOMLA_DB_HOST = "127.0.0.1"
|
||||
JOOMLA_DB_USER = "fejoomla3"
|
||||
JOOMLA_DB_PASS = "5FF-}5^[>7^pK4W9"
|
||||
JOOMLA_DB_NAME = "fejoomla3"
|
||||
|
||||
WP_DOCKER = "wordpress-mysql"
|
||||
WP_DB_USER = "wordpress_user"
|
||||
WP_DB_PASS = "wordpress_pass"
|
||||
WP_DB_NAME = "wordpress_db"
|
||||
|
||||
LAST_CONTENT_ID = 9043
|
||||
CARTA_CATIDS = {27, 40, 41}
|
||||
|
||||
CATID_TO_WP = {
|
||||
54: [26],
|
||||
77: [58],
|
||||
64: [41],
|
||||
52: [1],
|
||||
63: [40],
|
||||
61: [38],
|
||||
65: [31],
|
||||
}
|
||||
|
||||
DRY_RUN = '--dry-run' in sys.argv
|
||||
|
||||
# ── Helpers ────────────────────────────────────────────────────────────────────
|
||||
|
||||
def joomla_query(query: str) -> list[dict]:
|
||||
mysql_cmd = (f"mysql -h {JOOMLA_DB_HOST} -u {JOOMLA_DB_USER} "
|
||||
f"-p'{JOOMLA_DB_PASS}' {JOOMLA_DB_NAME} "
|
||||
f"--default-character-set=utf8mb4 -B")
|
||||
cmd = ['sshpass', '-p', JOOMLA_SSH_PASS,
|
||||
'ssh', f'{JOOMLA_SSH_USER}@{JOOMLA_SSH_HOST}', mysql_cmd]
|
||||
result = subprocess.run(cmd, input=query, capture_output=True,
|
||||
text=True, encoding='utf-8')
|
||||
if result.returncode != 0:
|
||||
print(f"[ERR SSH] {result.stderr[:300]}", file=sys.stderr)
|
||||
return []
|
||||
lines = result.stdout.strip().split('\n')
|
||||
if len(lines) < 2:
|
||||
return []
|
||||
headers = lines[0].split('\t')
|
||||
return [dict(zip(headers, line.split('\t'))) for line in lines[1:] if line]
|
||||
|
||||
|
||||
def wp_mysql(query: str) -> list[dict]:
|
||||
cmd = ['docker', 'exec', WP_DOCKER,
|
||||
'mysql', '-u', WP_DB_USER, f'-p{WP_DB_PASS}', WP_DB_NAME,
|
||||
'--default-character-set=utf8mb4', '-B', '-e', query]
|
||||
result = subprocess.run(cmd, capture_output=True, text=True, encoding='utf-8')
|
||||
if result.returncode != 0:
|
||||
return []
|
||||
lines = result.stdout.strip().split('\n')
|
||||
if len(lines) < 2:
|
||||
return []
|
||||
headers = lines[0].split('\t')
|
||||
return [dict(zip(headers, line.split('\t'))) for line in lines[1:] if line]
|
||||
|
||||
|
||||
def wp_execute(sql: str):
|
||||
if DRY_RUN:
|
||||
print(f" [DRY] {sql[:110]}")
|
||||
return
|
||||
cmd = ['docker', 'exec', WP_DOCKER,
|
||||
'mysql', '-u', WP_DB_USER, f'-p{WP_DB_PASS}', WP_DB_NAME,
|
||||
'--default-character-set=utf8mb4', '-e', sql]
|
||||
result = subprocess.run(cmd, capture_output=True, text=True)
|
||||
if result.returncode != 0:
|
||||
err = result.stderr.replace('mysql: [Warning] Using a password on the command line interface can be insecure.\n', '')
|
||||
if err.strip():
|
||||
print(f" [ERR] {err.strip()[:200]}", file=sys.stderr)
|
||||
|
||||
|
||||
def esc(s: str) -> str:
|
||||
return s.replace('\\', '\\\\').replace("'", "\\'")
|
||||
|
||||
|
||||
def unhex(val: str) -> str:
|
||||
if not val or val == 'NULL':
|
||||
return ''
|
||||
try:
|
||||
return bytes.fromhex(val).decode('utf-8', errors='replace')
|
||||
except Exception:
|
||||
return val
|
||||
|
||||
|
||||
def main():
|
||||
print(f"=== Import ew4r_content no-cartas (id > {LAST_CONTENT_ID}) "
|
||||
f"{'[DRY RUN]' if DRY_RUN else '[LIVE]'} ===\n")
|
||||
|
||||
# Cargar user map
|
||||
user_rows = wp_mysql(
|
||||
"SELECT um.meta_value jid, u.ID wid FROM wp_users u "
|
||||
"JOIN wp_usermeta um ON um.user_id=u.ID "
|
||||
"WHERE um.meta_key='_fgj2wp_old_user_id'"
|
||||
)
|
||||
user_map = {}
|
||||
for r in user_rows:
|
||||
try:
|
||||
user_map[int(r['jid'])] = int(r['wid'])
|
||||
except ValueError:
|
||||
pass
|
||||
print(f"Usuarios mapeados: {len(user_map)}")
|
||||
|
||||
# Cargar term_taxonomy_ids
|
||||
all_term_ids = sorted({t for cats in CATID_TO_WP.values() for t in cats} | {1})
|
||||
rows = wp_mysql(
|
||||
f"SELECT term_id, term_taxonomy_id FROM wp_term_taxonomy "
|
||||
f"WHERE term_id IN ({','.join(map(str,all_term_ids))}) AND taxonomy='category'"
|
||||
)
|
||||
tt_ids = {int(r['term_id']): int(r['term_taxonomy_id']) for r in rows}
|
||||
print(f"TT IDs: {tt_ids}")
|
||||
|
||||
# Polylang ES
|
||||
pl_rows = wp_mysql(
|
||||
"SELECT tt.term_taxonomy_id FROM wp_terms t "
|
||||
"JOIN wp_term_taxonomy tt ON tt.term_id=t.term_id "
|
||||
"WHERE tt.taxonomy='language' AND t.slug='es' LIMIT 1"
|
||||
)
|
||||
pl_es_tt = int(pl_rows[0]['term_taxonomy_id']) if pl_rows else None
|
||||
|
||||
# IDs ya en WP
|
||||
existing_rows = wp_mysql(
|
||||
f"SELECT meta_value FROM wp_postmeta "
|
||||
f"WHERE meta_key='_fgj2wp_old_content_id' AND meta_value+0 > {LAST_CONTENT_ID}"
|
||||
)
|
||||
existing_ids = {int(r['meta_value']) for r in existing_rows}
|
||||
print(f"IDs ya importados con id > {LAST_CONTENT_ID}: {len(existing_ids)}")
|
||||
|
||||
# Obtener items de Joomla
|
||||
print("\nObteniendo items de Joomla...")
|
||||
catids_excl = ','.join(str(c) for c in CARTA_CATIDS)
|
||||
query = (
|
||||
f"SELECT id, HEX(title) title, HEX(alias) alias, "
|
||||
f"HEX(introtext) introtext, HEX(`fulltext`) fulltext_col, "
|
||||
f"catid, created, created_by "
|
||||
f"FROM ew4r_content "
|
||||
f"WHERE state=1 AND id > {LAST_CONTENT_ID} AND catid NOT IN ({catids_excl}) "
|
||||
f"ORDER BY id;"
|
||||
)
|
||||
items = joomla_query(query)
|
||||
print(f"Items a importar: {len(items)}")
|
||||
|
||||
stats = {'ok': 0, 'skip': 0, 'err': 0}
|
||||
|
||||
for item in items:
|
||||
joomla_id = int(item['id'])
|
||||
catid = int(item['catid'])
|
||||
title = unhex(item.get('title', ''))
|
||||
alias = unhex(item.get('alias', ''))
|
||||
intro = unhex(item.get('introtext', ''))
|
||||
full = unhex(item.get('fulltext_col', ''))
|
||||
created = item.get('created', '') or datetime.now().strftime('%Y-%m-%d %H:%M:%S')
|
||||
created_by = int(item.get('created_by', 0) or 0)
|
||||
|
||||
if joomla_id in existing_ids:
|
||||
print(f" [SKIP] id={joomla_id} ya existe")
|
||||
stats['skip'] += 1
|
||||
continue
|
||||
|
||||
content = intro + ('\n<!--more-->\n' + full if full.strip() else '')
|
||||
wp_author = user_map.get(created_by, 1)
|
||||
wp_cats = CATID_TO_WP.get(catid, [1])
|
||||
|
||||
print(f" [{joomla_id}] catid={catid} | {title[:50]}")
|
||||
|
||||
wp_execute(
|
||||
f"INSERT INTO wp_posts "
|
||||
f"(post_author, post_date, post_date_gmt, post_content, post_title, "
|
||||
f"post_excerpt, post_status, comment_status, ping_status, post_name, "
|
||||
f"post_type, post_modified, post_modified_gmt, comment_count, "
|
||||
f"to_ping, pinged, post_content_filtered) VALUES ("
|
||||
f"{wp_author}, '{created}', '{created}', '{esc(content)}', "
|
||||
f"'{esc(title)}', '', 'publish', 'open', 'open', '{esc(alias[:200])}', "
|
||||
f"'post', '{created}', '{created}', 0, '', '', '')"
|
||||
)
|
||||
|
||||
if DRY_RUN:
|
||||
stats['ok'] += 1
|
||||
continue
|
||||
|
||||
new_id_rows = wp_mysql("SELECT MAX(ID) new_id FROM wp_posts")
|
||||
if not new_id_rows:
|
||||
stats['err'] += 1
|
||||
continue
|
||||
new_wp_id = int(new_id_rows[0]['new_id'])
|
||||
print(f" → WP ID={new_wp_id}")
|
||||
|
||||
# Metas
|
||||
wp_execute(f"INSERT INTO wp_postmeta (post_id, meta_key, meta_value) VALUES ({new_wp_id}, '_fgj2wp_old_content_id', '{joomla_id}')")
|
||||
|
||||
# Categorías
|
||||
for term_id in wp_cats:
|
||||
tt_id = tt_ids.get(term_id)
|
||||
if tt_id:
|
||||
wp_execute(
|
||||
f"INSERT IGNORE INTO wp_term_relationships (object_id, term_taxonomy_id) "
|
||||
f"VALUES ({new_wp_id}, {tt_id})"
|
||||
)
|
||||
|
||||
# Polylang ES
|
||||
if pl_es_tt:
|
||||
wp_execute(
|
||||
f"INSERT IGNORE INTO wp_term_relationships (object_id, term_taxonomy_id) "
|
||||
f"VALUES ({new_wp_id}, {pl_es_tt})"
|
||||
)
|
||||
|
||||
stats['ok'] += 1
|
||||
|
||||
if not DRY_RUN and stats['ok'] > 0:
|
||||
print("\nActualizando counts de categorías...")
|
||||
tt_str = ','.join(str(v) for v in tt_ids.values())
|
||||
wp_execute(
|
||||
f"UPDATE wp_term_taxonomy tt SET count = ("
|
||||
f"SELECT COUNT(*) FROM wp_term_relationships tr "
|
||||
f"WHERE tr.term_taxonomy_id=tt.term_taxonomy_id"
|
||||
f") WHERE tt.term_taxonomy_id IN ({tt_str})"
|
||||
)
|
||||
|
||||
print(f"\n=== Resultado: {stats['ok']} ok, {stats['skip']} skip, {stats['err']} err ===")
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
@@ -0,0 +1,390 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
import_new_k2_items.py
|
||||
|
||||
Importa los K2 items nuevos de Joomla prod (id > 17873) al WordPress local (Docker).
|
||||
Conexión a Joomla: SSH + MySQL en feadulta@134.0.10.170
|
||||
Conexión a WP: Docker exec wordpress-mysql
|
||||
|
||||
Categorías WP asignadas según extra_fields:
|
||||
- ES + tiene "libro de la biblia" (id 9) → Comentarios al evangelio (1647) + Feadulta (71)
|
||||
- ES + no id9 + título "DOMINGO/SEMANA SANTA/etc." → Eucaristía (1648) + Feadulta (71)
|
||||
- ES + no id9 + otro → Artículos (1650) + Feadulta (71)
|
||||
- No ES → Artículos (1650) + Feadulta (71)
|
||||
|
||||
Idioma Polylang asignado según extra_field id 16:
|
||||
1=es, 2=en, 3=fr, 4=it, 5=pt
|
||||
"""
|
||||
|
||||
import json
|
||||
import subprocess
|
||||
import sys
|
||||
from datetime import datetime
|
||||
|
||||
# ── Configuración ──────────────────────────────────────────────────────────────
|
||||
|
||||
JOOMLA_SSH_HOST = "134.0.10.170"
|
||||
JOOMLA_SSH_USER = "feadulta"
|
||||
JOOMLA_SSH_PASS = "6Rm2qOF@eundwpda"
|
||||
JOOMLA_DB_HOST = "127.0.0.1"
|
||||
JOOMLA_DB_USER = "fejoomla3"
|
||||
JOOMLA_DB_PASS = "5FF-}5^[>7^pK4W9"
|
||||
JOOMLA_DB_NAME = "fejoomla3"
|
||||
|
||||
WP_DOCKER = "wordpress-mysql"
|
||||
WP_DB_USER = "wordpress_user"
|
||||
WP_DB_PASS = "wordpress_pass"
|
||||
WP_DB_NAME = "wordpress_db"
|
||||
WP_DB_HOST = "wordpress-mysql" # dentro del container
|
||||
|
||||
LAST_K2_ID = 17873 # último ID importado en WP
|
||||
|
||||
# WP term_taxonomy_ids (obtenidos con SELECT tt.term_taxonomy_id FROM wp_term_taxonomy tt WHERE tt.term_id=N)
|
||||
# Precalculados:
|
||||
CAT_FEADULTA = 71 # term_id (se convertirá a term_taxonomy_id abajo)
|
||||
CAT_ARTICULOS = 1650
|
||||
CAT_EVANGELIO = 1647
|
||||
CAT_EUCARISTIA = 1648
|
||||
|
||||
LANG_MAP = {1: 'es', 2: 'en', 3: 'fr', 4: 'it', 5: 'pt'}
|
||||
DOMINGO_RE = r'DOMINGO|SEMANA SANTA|SEMANA DE PASCUA|PENTECOST|NAVIDAD|EPIFAN'
|
||||
|
||||
DRY_RUN = '--dry-run' in sys.argv
|
||||
|
||||
# ── Helpers ────────────────────────────────────────────────────────────────────
|
||||
|
||||
def ssh_mysql(query: str) -> list[dict]:
|
||||
"""Ejecuta una query en el MySQL de Joomla prod vía sshpass."""
|
||||
cmd = [
|
||||
'sshpass', '-p', JOOMLA_SSH_PASS,
|
||||
'ssh', f'{JOOMLA_SSH_USER}@{JOOMLA_SSH_HOST}',
|
||||
f'mysql -h {JOOMLA_DB_HOST} -u {JOOMLA_DB_USER} '
|
||||
f'-p{repr(JOOMLA_DB_PASS)} {JOOMLA_DB_NAME} '
|
||||
f'--default-character-set=utf8mb4 -B -e "{query}"'
|
||||
]
|
||||
result = subprocess.run(cmd, capture_output=True, text=True, encoding='utf-8')
|
||||
if result.returncode != 0:
|
||||
print(f"[ERROR SSH] {result.stderr[:300]}", file=sys.stderr)
|
||||
return []
|
||||
lines = result.stdout.strip().split('\n')
|
||||
if len(lines) < 2:
|
||||
return []
|
||||
headers = lines[0].split('\t')
|
||||
rows = []
|
||||
for line in lines[1:]:
|
||||
if line:
|
||||
vals = line.split('\t')
|
||||
rows.append(dict(zip(headers, vals)))
|
||||
return rows
|
||||
|
||||
|
||||
def wp_mysql(query: str) -> list[dict]:
|
||||
"""Ejecuta una query en el MySQL del WP local vía Docker exec."""
|
||||
cmd = [
|
||||
'docker', 'exec', WP_DOCKER,
|
||||
'mysql', '-u', WP_DB_USER, f'-p{WP_DB_PASS}', WP_DB_NAME,
|
||||
'--default-character-set=utf8mb4', '-B', '-e', query
|
||||
]
|
||||
result = subprocess.run(cmd, capture_output=True, text=True, encoding='utf-8')
|
||||
if result.returncode != 0:
|
||||
print(f"[ERROR WP] {result.stderr[:300]}", file=sys.stderr)
|
||||
return []
|
||||
lines = result.stdout.strip().split('\n')
|
||||
if len(lines) < 2:
|
||||
return []
|
||||
headers = lines[0].split('\t')
|
||||
rows = []
|
||||
for line in lines[1:]:
|
||||
if line:
|
||||
vals = line.split('\t')
|
||||
rows.append(dict(zip(headers, vals)))
|
||||
return rows
|
||||
|
||||
|
||||
def wp_execute(sql: str):
|
||||
"""Ejecuta un INSERT/UPDATE en WP MySQL."""
|
||||
if DRY_RUN:
|
||||
print(f" [DRY] {sql[:120]}")
|
||||
return
|
||||
cmd = [
|
||||
'docker', 'exec', WP_DOCKER,
|
||||
'mysql', '-u', WP_DB_USER, f'-p{WP_DB_PASS}', WP_DB_NAME,
|
||||
'--default-character-set=utf8mb4', '-e', sql
|
||||
]
|
||||
result = subprocess.run(cmd, capture_output=True, text=True)
|
||||
if result.returncode != 0:
|
||||
print(f"[ERROR INSERT] {result.stderr[:300]}", file=sys.stderr)
|
||||
|
||||
|
||||
def esc(s: str) -> str:
|
||||
"""Escapa una string para SQL."""
|
||||
return s.replace('\\', '\\\\').replace("'", "\\'")
|
||||
|
||||
|
||||
# ── Cargar datos auxiliares ────────────────────────────────────────────────────
|
||||
|
||||
def load_user_map() -> dict:
|
||||
"""Devuelve {joomla_user_id: wp_user_id}."""
|
||||
rows = wp_mysql(
|
||||
"SELECT um.meta_value jid, u.ID wid FROM wp_users u "
|
||||
"JOIN wp_usermeta um ON um.user_id=u.ID "
|
||||
"WHERE um.meta_key='_fgj2wp_old_user_id'"
|
||||
)
|
||||
m = {}
|
||||
for r in rows:
|
||||
try:
|
||||
m[int(r['jid'])] = int(r['wid'])
|
||||
except ValueError:
|
||||
pass
|
||||
return m
|
||||
|
||||
|
||||
def load_term_taxonomy_ids() -> dict:
|
||||
"""Devuelve {term_id: term_taxonomy_id} para las categorías relevantes."""
|
||||
term_ids = [CAT_FEADULTA, CAT_ARTICULOS, CAT_EVANGELIO, CAT_EUCARISTIA]
|
||||
ids_str = ','.join(str(x) for x in term_ids)
|
||||
rows = wp_mysql(
|
||||
f"SELECT term_id, term_taxonomy_id FROM wp_term_taxonomy "
|
||||
f"WHERE term_id IN ({ids_str}) AND taxonomy='category'"
|
||||
)
|
||||
return {int(r['term_id']): int(r['term_taxonomy_id']) for r in rows}
|
||||
|
||||
|
||||
def load_polylang_term_ids() -> dict:
|
||||
"""Devuelve {'es': tt_id, 'en': tt_id, ...} para los términos de idioma de Polylang."""
|
||||
rows = wp_mysql(
|
||||
"SELECT t.slug, tt.term_taxonomy_id FROM wp_terms t "
|
||||
"JOIN wp_term_taxonomy tt ON tt.term_id=t.term_id "
|
||||
"WHERE tt.taxonomy='language' AND t.slug IN ('es','en','fr','it','pt')"
|
||||
)
|
||||
return {r['slug']: int(r['term_taxonomy_id']) for r in rows}
|
||||
|
||||
|
||||
# ── Parsear extra_fields ───────────────────────────────────────────────────────
|
||||
|
||||
def parse_extra_fields(ef_json: str) -> dict:
|
||||
"""Devuelve dict con claves: lang_val, has_libro, cita_biblica."""
|
||||
result = {'lang_val': None, 'has_libro': False, 'cita_biblica': None}
|
||||
if not ef_json or ef_json == 'NULL':
|
||||
return result
|
||||
try:
|
||||
fields = json.loads(ef_json)
|
||||
except json.JSONDecodeError:
|
||||
return result
|
||||
for f in fields:
|
||||
fid = str(f.get('id', ''))
|
||||
val = f.get('value')
|
||||
if fid == '16' and val is not None:
|
||||
try:
|
||||
result['lang_val'] = int(val)
|
||||
except (ValueError, TypeError):
|
||||
pass
|
||||
elif fid == '9':
|
||||
result['has_libro'] = True
|
||||
elif fid == '14':
|
||||
if isinstance(val, list):
|
||||
result['cita_biblica'] = ','.join(str(v) for v in val)
|
||||
else:
|
||||
result['cita_biblica'] = str(val) if val else None
|
||||
return result
|
||||
|
||||
|
||||
def determine_categories(ef: dict, title: str) -> list[int]:
|
||||
"""Devuelve lista de term_ids de categoría para el post."""
|
||||
import re
|
||||
lang = ef.get('lang_val')
|
||||
es = (lang == 1 or lang is None)
|
||||
cats = [CAT_FEADULTA]
|
||||
if es and ef.get('has_libro'):
|
||||
cats.append(CAT_EVANGELIO)
|
||||
elif es and re.search(DOMINGO_RE, title, re.IGNORECASE):
|
||||
cats.append(CAT_EUCARISTIA)
|
||||
else:
|
||||
cats.append(CAT_ARTICULOS)
|
||||
return cats
|
||||
|
||||
|
||||
# ── Import principal ───────────────────────────────────────────────────────────
|
||||
|
||||
def main():
|
||||
print(f"=== Import K2 items > {LAST_K2_ID} → WP local {'[DRY RUN]' if DRY_RUN else '[LIVE]'} ===\n")
|
||||
|
||||
user_map = load_user_map()
|
||||
print(f"Usuarios mapeados: {len(user_map)}")
|
||||
|
||||
tt_ids = load_term_taxonomy_ids()
|
||||
print(f"Categorías TT IDs: {tt_ids}")
|
||||
|
||||
pl_ids = load_polylang_term_ids()
|
||||
print(f"Polylang idiomas: {pl_ids}")
|
||||
|
||||
# Verificar que los K2 IDs ya en WP no se reimportan
|
||||
existing = wp_mysql(
|
||||
f"SELECT meta_value FROM wp_postmeta WHERE meta_key='_fgj2wp_old_k2_id' "
|
||||
f"AND meta_value+0 > {LAST_K2_ID}"
|
||||
)
|
||||
existing_ids = {int(r['meta_value']) for r in existing}
|
||||
print(f"K2 IDs > {LAST_K2_ID} ya en WP: {len(existing_ids)}")
|
||||
|
||||
# Obtener items de Joomla vía SSH+MySQL (query por stdin para evitar escape de shell)
|
||||
print("\nObteniendo K2 items de Joomla prod...")
|
||||
# HEX encoding para campos de texto (evita que el HTML con saltos de línea
|
||||
# rompa el parsing TSV)
|
||||
query = (
|
||||
f"SELECT id, HEX(title) title, HEX(alias) alias, "
|
||||
f"HEX(introtext) introtext, HEX(`fulltext`) fulltext_col, "
|
||||
f"created, created_by, HEX(extra_fields) extra_fields, publish_up "
|
||||
f"FROM ew4r_k2_items "
|
||||
f"WHERE published=1 AND id > {LAST_K2_ID} ORDER BY id;"
|
||||
)
|
||||
mysql_cmd = (
|
||||
f"mysql -h {JOOMLA_DB_HOST} -u {JOOMLA_DB_USER} "
|
||||
f"-p'{JOOMLA_DB_PASS}' {JOOMLA_DB_NAME} "
|
||||
f"--default-character-set=utf8mb4 -B"
|
||||
)
|
||||
cmd = [
|
||||
'sshpass', '-p', JOOMLA_SSH_PASS,
|
||||
'ssh', f'{JOOMLA_SSH_USER}@{JOOMLA_SSH_HOST}',
|
||||
mysql_cmd
|
||||
]
|
||||
result = subprocess.run(cmd, input=query, capture_output=True, text=True, encoding='utf-8')
|
||||
if result.returncode != 0:
|
||||
print(f"ERROR: {result.stderr[:500]}")
|
||||
sys.exit(1)
|
||||
|
||||
lines = result.stdout.strip().split('\n')
|
||||
if len(lines) < 2:
|
||||
print("No se encontraron items nuevos.")
|
||||
return
|
||||
|
||||
headers = lines[0].split('\t')
|
||||
items = []
|
||||
for line in lines[1:]:
|
||||
if line:
|
||||
vals = line.split('\t')
|
||||
items.append(dict(zip(headers, vals)))
|
||||
|
||||
print(f"Items a importar: {len(items)}")
|
||||
|
||||
stats = {'ok': 0, 'skip': 0, 'err': 0}
|
||||
|
||||
for item in items:
|
||||
k2_id = int(item['id'])
|
||||
|
||||
if k2_id in existing_ids:
|
||||
print(f" [SKIP] K2 id={k2_id} ya existe en WP")
|
||||
stats['skip'] += 1
|
||||
continue
|
||||
|
||||
def unhex(val: str) -> str:
|
||||
if not val or val == 'NULL':
|
||||
return ''
|
||||
try:
|
||||
return bytes.fromhex(val).decode('utf-8', errors='replace')
|
||||
except Exception:
|
||||
return val
|
||||
|
||||
title = unhex(item.get('title', ''))
|
||||
alias = unhex(item.get('alias', ''))
|
||||
intro = unhex(item.get('introtext', ''))
|
||||
full = unhex(item.get('fulltext_col', ''))
|
||||
ef_json = unhex(item.get('extra_fields', '')) or '[]'
|
||||
created = item.get('created', '') or datetime.now().strftime('%Y-%m-%d %H:%M:%S')
|
||||
if not created or created == 'NULL':
|
||||
created = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
|
||||
created_by_raw = item.get('created_by', '0')
|
||||
created_by = int(created_by_raw) if created_by_raw and created_by_raw != 'NULL' else 0
|
||||
|
||||
# Contenido combinado
|
||||
if full and full.strip():
|
||||
content = intro + '\n<!--more-->\n' + full
|
||||
else:
|
||||
content = intro
|
||||
|
||||
# Autor WP
|
||||
wp_author = user_map.get(created_by, 1) # fallback: admin
|
||||
|
||||
# Extra fields
|
||||
ef = parse_extra_fields(ef_json)
|
||||
lang_code = LANG_MAP.get(ef.get('lang_val'), 'es')
|
||||
cats = determine_categories(ef, title)
|
||||
|
||||
print(f" [{k2_id}] {title[:50]} | lang={lang_code} | cats={cats}")
|
||||
|
||||
# INSERT post
|
||||
post_slug = esc(alias[:200]) if alias else ''
|
||||
post_title = esc(title)
|
||||
post_content = esc(content)
|
||||
post_date = created
|
||||
post_date_gmt = created # simplificado (no ajuste TZ)
|
||||
|
||||
insert_post = (
|
||||
f"INSERT INTO wp_posts "
|
||||
f"(post_author, post_date, post_date_gmt, post_content, post_title, "
|
||||
f"post_excerpt, post_status, comment_status, ping_status, post_name, "
|
||||
f"post_type, post_modified, post_modified_gmt, comment_count, "
|
||||
f"to_ping, pinged, post_content_filtered) VALUES ("
|
||||
f"{wp_author}, '{post_date}', '{post_date_gmt}', '{post_content}', "
|
||||
f"'{post_title}', '', 'publish', 'open', 'open', '{post_slug}', "
|
||||
f"'post', '{post_date}', '{post_date_gmt}', 0, '', '', '')"
|
||||
)
|
||||
wp_execute(insert_post)
|
||||
|
||||
if DRY_RUN:
|
||||
stats['ok'] += 1
|
||||
continue
|
||||
|
||||
# Obtener el ID del post recién insertado
|
||||
new_id_rows = wp_mysql("SELECT LAST_INSERT_ID() as new_id")
|
||||
if not new_id_rows:
|
||||
print(f" [ERROR] No se pudo obtener LAST_INSERT_ID para k2_id={k2_id}")
|
||||
stats['err'] += 1
|
||||
continue
|
||||
new_wp_id = int(new_id_rows[0]['new_id'])
|
||||
print(f" → WP post ID={new_wp_id}")
|
||||
|
||||
# INSERT metas
|
||||
metas = [
|
||||
('_fgj2wp_old_k2_id', str(k2_id)),
|
||||
('Idioma', str(ef.get('lang_val') or 1)),
|
||||
]
|
||||
for meta_key, meta_val in metas:
|
||||
wp_execute(
|
||||
f"INSERT INTO wp_postmeta (post_id, meta_key, meta_value) "
|
||||
f"VALUES ({new_wp_id}, '{esc(meta_key)}', '{esc(meta_val)}')"
|
||||
)
|
||||
|
||||
# Categorías
|
||||
for term_id in cats:
|
||||
tt_id = tt_ids.get(term_id)
|
||||
if tt_id:
|
||||
wp_execute(
|
||||
f"INSERT IGNORE INTO wp_term_relationships (object_id, term_taxonomy_id) "
|
||||
f"VALUES ({new_wp_id}, {tt_id})"
|
||||
)
|
||||
|
||||
# Polylang language
|
||||
pl_tt = pl_ids.get(lang_code)
|
||||
if pl_tt:
|
||||
wp_execute(
|
||||
f"INSERT IGNORE INTO wp_term_relationships (object_id, term_taxonomy_id) "
|
||||
f"VALUES ({new_wp_id}, {pl_tt})"
|
||||
)
|
||||
|
||||
stats['ok'] += 1
|
||||
|
||||
# Actualizar counts de categorías
|
||||
if not DRY_RUN and stats['ok'] > 0:
|
||||
print("\nActualizando counts de categorías...")
|
||||
tt_ids_list = ','.join(str(v) for v in tt_ids.values())
|
||||
wp_execute(
|
||||
f"UPDATE wp_term_taxonomy tt SET count = ("
|
||||
f"SELECT COUNT(*) FROM wp_term_relationships tr WHERE tr.term_taxonomy_id=tt.term_taxonomy_id"
|
||||
f") WHERE tt.term_taxonomy_id IN ({tt_ids_list})"
|
||||
)
|
||||
|
||||
print(f"\n=== Resultado: {stats['ok']} ok, {stats['skip']} skip, {stats['err']} err ===")
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
@@ -749,6 +749,80 @@ add_shortcode('fea_multimedia', function($atts) {
|
||||
return $html . '</div></section>';
|
||||
});
|
||||
|
||||
// ── Shortcode: [fea_prefooter] — 3 columnas sobre el footer ──────────────────
|
||||
add_shortcode('fea_prefooter', function() {
|
||||
$uploads = wp_upload_dir()['baseurl'];
|
||||
|
||||
// Columna centro: última noticia de alcance (cat term_id=41)
|
||||
$latest_noticias = get_posts([
|
||||
'posts_per_page' => 1,
|
||||
'category__in' => [fea_cat(41)],
|
||||
'post_status' => 'publish',
|
||||
'orderby' => 'date',
|
||||
'order' => 'DESC',
|
||||
]);
|
||||
$cat_noticias_url = get_category_link(fea_cat(41));
|
||||
$noticia_title = !empty($latest_noticias) ? fea_title($latest_noticias[0]->post_title) : '';
|
||||
$noticia_url = !empty($latest_noticias) ? get_permalink($latest_noticias[0]->ID) : $cat_noticias_url;
|
||||
|
||||
// Columna derecha: último vídeo (cat term_id=58)
|
||||
$latest_video = get_posts([
|
||||
'posts_per_page' => 1,
|
||||
'category__in' => [fea_cat(58)],
|
||||
'post_status' => 'publish',
|
||||
'orderby' => 'date',
|
||||
'order' => 'DESC',
|
||||
]);
|
||||
$video_url = !empty($latest_video) ? get_permalink($latest_video[0]->ID) : get_category_link(fea_cat(58));
|
||||
|
||||
$effa_url = get_permalink(42726);
|
||||
$suma_url = get_permalink(18036);
|
||||
$libros_url = get_category_link(1616);
|
||||
$videos_escuela_url = get_permalink(21921);
|
||||
|
||||
ob_start(); ?>
|
||||
<div class="fea-prefooter">
|
||||
<div class="fea-prefooter-col">
|
||||
<a href="<?php echo esc_url($libros_url); ?>">
|
||||
<img src="<?php echo esc_url($uploads . '/banners/como_adquirir_nuestros_libros.gif'); ?>" alt="Cómo adquirir nuestros libros" style="display:block;margin:0 auto 8px;" />
|
||||
</a>
|
||||
<a href="<?php echo esc_url($videos_escuela_url); ?>">
|
||||
<img src="<?php echo esc_url($uploads . '/quienes_somos/ultimos_videos.jpg'); ?>" alt="Últimos vídeos de la escuela" width="282" height="97" style="display:block;margin:0 auto;" />
|
||||
</a>
|
||||
</div>
|
||||
<div class="fea-prefooter-col fea-prefooter-center">
|
||||
<a href="<?php echo esc_url($cat_noticias_url); ?>">
|
||||
<img src="<?php echo esc_url($uploads . '/recursos/noticias_2025.jpg'); ?>" alt="Noticias de alcance" width="300" height="340" style="display:block;margin:0 auto;" />
|
||||
</a>
|
||||
<?php if ($noticia_title): ?>
|
||||
<p class="fea-prefooter-noticia">
|
||||
<a href="<?php echo esc_url($noticia_url); ?>"><?php echo esc_html($noticia_title); ?></a>
|
||||
</p>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
<div class="fea-prefooter-col">
|
||||
<a href="<?php echo esc_url($suma_url); ?>">
|
||||
<img src="<?php echo esc_url($uploads . '/banners/este_portal.gif'); ?>" alt="Este portal" style="display:block;margin:0 auto 5px;" />
|
||||
</a>
|
||||
<a href="<?php echo esc_url($effa_url); ?>">
|
||||
<img src="<?php echo esc_url($uploads . '/banners/acceso_a_EFFA.jpg'); ?>" alt="Acceso a EFFA" style="display:block;margin:0 auto 5px;" />
|
||||
</a>
|
||||
<a href="<?php echo esc_url($video_url); ?>">
|
||||
<img src="<?php echo esc_url($uploads . '/banners/video_de_la_semana1.jpg'); ?>" alt="Vídeo de la semana" style="display:block;margin:0 auto;" />
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<?php
|
||||
$css = '<style>
|
||||
.fea-prefooter{display:flex;gap:1.5rem;justify-content:center;align-items:flex-start;padding:2rem 1rem;border-top:2px solid #e5e5e5;margin-top:3rem;}
|
||||
.fea-prefooter-col{flex:1;max-width:320px;text-align:center;}
|
||||
.fea-prefooter-noticia{margin-top:0.6rem;font-size:0.85rem;font-weight:600;color:#0000cc;line-height:1.3;}
|
||||
.fea-prefooter-noticia a{color:#0000cc;}
|
||||
@media(max-width:640px){.fea-prefooter{flex-direction:column;align-items:center;}.fea-prefooter-col{max-width:100%;}}
|
||||
</style>';
|
||||
return $css . ob_get_clean();
|
||||
});
|
||||
|
||||
// ── Reescribir links internos al idioma activo (Polylang) ─────────────────
|
||||
add_filter('the_content', function($content) {
|
||||
if (!function_exists('pll_current_language') || !function_exists('pll_get_post')) return $content;
|
||||
|
||||
Reference in New Issue
Block a user