Añadir mu-plugins y scripts de feadulta
This commit is contained in:
@@ -0,0 +1,289 @@
|
||||
<?php
|
||||
/**
|
||||
* Helper PHP para translate_post.py — corre DENTRO del contenedor WP cargando wp-load.php
|
||||
* (no necesita wp-cli ni proc_open). Centraliza la lógica de WordPress/Polylang.
|
||||
*
|
||||
* Uso (vía `docker exec wordpress-web php /tmp/fea_translate_helper.php <subcomando> ...`):
|
||||
* read <id> → JSON {id,title,content,excerpt,lang,status,author,date,cats}
|
||||
* read_full <id> → JSON con slug, metas, categorías y grupo Polylang
|
||||
* exists <es_id> <lang> → imprime el ID de la traducción en <lang> (0 si no hay)
|
||||
* create <es_id> <lang> <status> (lee {title,content} por stdin)
|
||||
* → crea el post traducido, lo enlaza con Polylang y mete metas;
|
||||
* imprime el nuevo ID.
|
||||
* clone <target_id> <lang> <status> (lee payload JSON por stdin)
|
||||
* → inserta/actualiza un post con ID explícito, categorías y metas.
|
||||
* save_translations → guarda un grupo Polylang exacto leído por stdin.
|
||||
*
|
||||
* Ver issue rafa/feadulta#75.
|
||||
*/
|
||||
|
||||
// Bootstrap portable. Si WP no está cargado (modo standalone), cargar wp-load.
|
||||
// Local (docker): /var/www/html/wp-load.php (por defecto).
|
||||
// Prod: export FEA_WP_LOAD=/web/wp-nuevo/wp-load.php
|
||||
// (Si se ejecuta vía `wp eval-file`, ABSPATH ya está definido y no se recarga.)
|
||||
if (!defined('ABSPATH')) {
|
||||
$_SERVER['REQUEST_URI'] = $_SERVER['REQUEST_URI'] ?? '/';
|
||||
$_SERVER['HTTP_HOST'] = $_SERVER['HTTP_HOST'] ?? 'localhost';
|
||||
require_once (getenv('FEA_WP_LOAD') ?: '/var/www/html/wp-load.php');
|
||||
}
|
||||
|
||||
if (!function_exists('pll_set_post_language')) {
|
||||
fwrite(STDERR, "Polylang no disponible\n");
|
||||
exit(2);
|
||||
}
|
||||
|
||||
$cmd = $argv[1] ?? '';
|
||||
|
||||
function out_json($data): void { echo wp_json_encode($data); }
|
||||
|
||||
function meta_payload(int $id): array {
|
||||
$raw = get_post_meta($id);
|
||||
$out = [];
|
||||
foreach ($raw as $key => $values) {
|
||||
if (in_array($key, ['_edit_lock', '_edit_last'], true)) {
|
||||
continue;
|
||||
}
|
||||
$out[$key] = array_map('maybe_unserialize', (array) $values);
|
||||
}
|
||||
return $out;
|
||||
}
|
||||
|
||||
function normalize_meta_input(array $payload): array {
|
||||
$meta = $payload['meta'] ?? [];
|
||||
if (!is_array($meta)) {
|
||||
return [];
|
||||
}
|
||||
$out = [];
|
||||
foreach ($meta as $key => $values) {
|
||||
if (!is_string($key) || $key === '') {
|
||||
continue;
|
||||
}
|
||||
if (!is_array($values)) {
|
||||
$values = [$values];
|
||||
}
|
||||
$out[$key] = $values;
|
||||
}
|
||||
return $out;
|
||||
}
|
||||
|
||||
function set_meta_payload(int $id, array $meta): void {
|
||||
foreach ($meta as $key => $values) {
|
||||
delete_post_meta($id, $key);
|
||||
foreach ($values as $value) {
|
||||
add_post_meta($id, $key, maybe_serialize($value));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
switch ($cmd) {
|
||||
case 'read': {
|
||||
$id = (int) ($argv[2] ?? 0);
|
||||
$p = get_post($id);
|
||||
if (!$p) { fwrite(STDERR, "post $id no existe\n"); exit(3); }
|
||||
out_json([
|
||||
'id' => $p->ID,
|
||||
'title' => $p->post_title,
|
||||
'content' => $p->post_content,
|
||||
'excerpt' => $p->post_excerpt,
|
||||
'lang' => function_exists('pll_get_post_language') ? pll_get_post_language($id) : '',
|
||||
'status' => $p->post_status,
|
||||
'author' => (int) $p->post_author,
|
||||
'date' => $p->post_date,
|
||||
'cats' => wp_get_post_categories($id),
|
||||
]);
|
||||
break;
|
||||
}
|
||||
|
||||
case 'read_full': {
|
||||
$id = (int) ($argv[2] ?? 0);
|
||||
$p = get_post($id);
|
||||
if (!$p) { fwrite(STDERR, "post $id no existe\n"); exit(3); }
|
||||
out_json([
|
||||
'id' => $p->ID,
|
||||
'title' => $p->post_title,
|
||||
'content' => $p->post_content,
|
||||
'excerpt' => $p->post_excerpt,
|
||||
'slug' => $p->post_name,
|
||||
'lang' => function_exists('pll_get_post_language') ? pll_get_post_language($id) : '',
|
||||
'status' => $p->post_status,
|
||||
'author' => (int) $p->post_author,
|
||||
'date' => $p->post_date,
|
||||
'date_gmt' => $p->post_date_gmt,
|
||||
'type' => $p->post_type,
|
||||
'cats' => wp_get_post_categories($id),
|
||||
'cat_slugs' => array_values(array_map(static fn($t) => $t->slug, get_the_terms($id, 'category') ?: [])),
|
||||
'meta' => meta_payload($id),
|
||||
'translations' => function_exists('pll_get_post_translations') ? pll_get_post_translations($id) : [],
|
||||
]);
|
||||
break;
|
||||
}
|
||||
|
||||
case 'exists': {
|
||||
$es = (int) ($argv[2] ?? 0);
|
||||
$lang = (string) ($argv[3] ?? '');
|
||||
$t = (int) pll_get_post($es, $lang);
|
||||
if ($t && !get_post($t)) $t = 0; // enlace colgado a un post borrado
|
||||
echo $t;
|
||||
break;
|
||||
}
|
||||
|
||||
case 'unlink': {
|
||||
// Borra la traducción en <lang> y la saca del grupo (para --force / limpieza).
|
||||
$es = (int) ($argv[2] ?? 0);
|
||||
$lang = (string) ($argv[3] ?? '');
|
||||
$t = (int) pll_get_post($es, $lang);
|
||||
if ($t && get_post($t)) wp_delete_post($t, true);
|
||||
$tr = function_exists('pll_get_post_translations') ? pll_get_post_translations($es) : ['es' => $es];
|
||||
unset($tr[$lang]);
|
||||
if ($tr) pll_save_post_translations($tr);
|
||||
echo $t;
|
||||
break;
|
||||
}
|
||||
|
||||
case 'create': {
|
||||
$es = (int) ($argv[2] ?? 0);
|
||||
$lang = (string) ($argv[3] ?? '');
|
||||
$status = (string) ($argv[4] ?? 'draft');
|
||||
$src = get_post($es);
|
||||
if (!$src) { fwrite(STDERR, "post fuente $es no existe\n"); exit(3); }
|
||||
|
||||
$payload = json_decode(file_get_contents('php://stdin'), true);
|
||||
if (!is_array($payload) || empty($payload['title'])) {
|
||||
fwrite(STDERR, "payload inválido por stdin\n"); exit(4);
|
||||
}
|
||||
|
||||
// ¿ya existe (y vivo)? idempotencia dura.
|
||||
$existing = (int) pll_get_post($es, $lang);
|
||||
if ($existing && !get_post($existing)) $existing = 0;
|
||||
if ($existing) { echo $existing; break; }
|
||||
|
||||
$new_id = wp_insert_post([
|
||||
'post_title' => wp_slash($payload['title']),
|
||||
'post_content' => wp_slash($payload['content'] ?? ''),
|
||||
'post_excerpt' => wp_slash($payload['excerpt'] ?? ''),
|
||||
'post_name' => sanitize_title($payload['title']),
|
||||
'post_status' => $status,
|
||||
'post_type' => 'post',
|
||||
'post_author' => (int) $src->post_author,
|
||||
'post_date' => $src->post_date,
|
||||
'to_ping' => '',
|
||||
'pinged' => '',
|
||||
], true);
|
||||
|
||||
if (is_wp_error($new_id)) { fwrite(STDERR, $new_id->get_error_message() . "\n"); exit(5); }
|
||||
|
||||
// Idioma primero, para que las categorías traducidas casen con el idioma del post.
|
||||
pll_set_post_language($new_id, $lang);
|
||||
|
||||
// Categorías: mapea cada categoría ES a su traducción en el idioma destino
|
||||
// (las categorías de carta ya están traducidas: cartasemana 6→en 3077, fr 3083…).
|
||||
$cats = wp_get_post_categories($es);
|
||||
$mapped = [];
|
||||
foreach ($cats as $c) {
|
||||
$tc = function_exists('pll_get_term') ? (int) pll_get_term($c, $lang) : 0;
|
||||
$mapped[] = $tc ?: $c; // traducida si existe; si no, la ES (fallback)
|
||||
}
|
||||
if ($mapped) wp_set_post_categories($new_id, array_values(array_unique($mapped)));
|
||||
|
||||
// Enlace de traducción (preservando el grupo existente).
|
||||
$tr = function_exists('pll_get_post_translations') ? pll_get_post_translations($es) : ['es' => $es];
|
||||
if (!$tr) $tr = ['es' => $es];
|
||||
$tr[$lang] = $new_id;
|
||||
pll_save_post_translations($tr);
|
||||
|
||||
// Metas de trazabilidad.
|
||||
update_post_meta($new_id, 'traduccion_automatica', '1');
|
||||
update_post_meta($new_id, 'traduccion_origen', $es);
|
||||
update_post_meta($new_id, 'traduccion_modelo', $payload['model'] ?? '');
|
||||
update_post_meta($new_id, 'traduccion_fecha', gmdate('c'));
|
||||
|
||||
echo $new_id;
|
||||
break;
|
||||
}
|
||||
|
||||
case 'clone': {
|
||||
$target = (int) ($argv[2] ?? 0);
|
||||
$lang = (string) ($argv[3] ?? '');
|
||||
$status = (string) ($argv[4] ?? 'draft');
|
||||
if ($target <= 0 || $lang === '') {
|
||||
fwrite(STDERR, "uso: clone <target_id> <lang> <status>\n"); exit(6);
|
||||
}
|
||||
|
||||
$payload = json_decode(file_get_contents('php://stdin'), true);
|
||||
if (!is_array($payload) || empty($payload['title'])) {
|
||||
fwrite(STDERR, "payload inválido por stdin\n"); exit(4);
|
||||
}
|
||||
|
||||
$postarr = [
|
||||
'post_title' => wp_slash($payload['title']),
|
||||
'post_content' => wp_slash($payload['content'] ?? ''),
|
||||
'post_excerpt' => wp_slash($payload['excerpt'] ?? ''),
|
||||
'post_status' => $status ?: ($payload['status'] ?? 'draft'),
|
||||
'post_type' => $payload['type'] ?? 'post',
|
||||
'post_author' => (int) ($payload['author'] ?? 1),
|
||||
'post_date' => $payload['date'] ?? current_time('mysql'),
|
||||
'post_date_gmt'=> $payload['date_gmt'] ?? current_time('mysql', true),
|
||||
'post_name' => $payload['slug'] ?? '',
|
||||
'to_ping' => '',
|
||||
'pinged' => '',
|
||||
];
|
||||
|
||||
$existing = get_post($target);
|
||||
if ($existing) {
|
||||
$postarr['ID'] = $target;
|
||||
$new_id = wp_update_post($postarr, true);
|
||||
} else {
|
||||
$postarr['import_id'] = $target;
|
||||
$new_id = wp_insert_post($postarr, true);
|
||||
}
|
||||
|
||||
if (is_wp_error($new_id)) { fwrite(STDERR, $new_id->get_error_message() . "\n"); exit(5); }
|
||||
if ((int) $new_id !== $target) {
|
||||
fwrite(STDERR, "ID preservado falló: esperado $target, creado $new_id\n"); exit(7);
|
||||
}
|
||||
|
||||
pll_set_post_language($new_id, $lang);
|
||||
|
||||
$cats = [];
|
||||
foreach ((array) ($payload['cat_slugs'] ?? []) as $slug) {
|
||||
$term = get_term_by('slug', (string) $slug, 'category');
|
||||
if ($term && !is_wp_error($term)) {
|
||||
$cats[] = (int) $term->term_id;
|
||||
}
|
||||
}
|
||||
if (!$cats) {
|
||||
$cats = array_values(array_unique(array_map('intval', (array) ($payload['cats'] ?? []))));
|
||||
}
|
||||
wp_set_post_categories($new_id, $cats);
|
||||
|
||||
set_meta_payload($new_id, normalize_meta_input($payload));
|
||||
clean_post_cache($new_id);
|
||||
echo $new_id;
|
||||
break;
|
||||
}
|
||||
|
||||
case 'save_translations': {
|
||||
$payload = json_decode(file_get_contents('php://stdin'), true);
|
||||
if (!is_array($payload) || empty($payload['translations']) || !is_array($payload['translations'])) {
|
||||
fwrite(STDERR, "payload inválido por stdin\n"); exit(4);
|
||||
}
|
||||
$tr = [];
|
||||
foreach ($payload['translations'] as $lang => $id) {
|
||||
$id = (int) $id;
|
||||
if (!is_string($lang) || $lang === '' || $id <= 0 || !get_post($id)) {
|
||||
continue;
|
||||
}
|
||||
$tr[$lang] = $id;
|
||||
}
|
||||
if (count($tr) < 2) {
|
||||
fwrite(STDERR, "grupo insuficiente\n"); exit(8);
|
||||
}
|
||||
pll_save_post_translations($tr);
|
||||
out_json($tr);
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
fwrite(STDERR, "subcomando desconocido: '$cmd'\n");
|
||||
exit(1);
|
||||
}
|
||||
Reference in New Issue
Block a user