feat: add REST endpoint to create Polylang translations
This commit is contained in:
@@ -0,0 +1,169 @@
|
||||
<?php
|
||||
/**
|
||||
* Plugin Name: Fe Adulta — API crear traducción
|
||||
* Description: Endpoint REST idempotente para crear y enlazar traducciones Polylang.
|
||||
* Version: 1.0
|
||||
*
|
||||
* POST /wp-json/fea/v1/crear-traduccion
|
||||
* es_id=<post ES>, lang=<en|fr|it|pt>, title/content/excerpt/status/model
|
||||
*
|
||||
* Ver issue gitea.feadulta.com/rafa/feadulta#222.
|
||||
*/
|
||||
|
||||
if (!defined('ABSPATH')) exit;
|
||||
|
||||
const FEA_TRANSLATION_LANGUAGES = ['en', 'fr', 'it', 'pt'];
|
||||
|
||||
add_action('rest_api_init', function () {
|
||||
register_rest_route('fea/v1', '/crear-traduccion', [
|
||||
'methods' => WP_REST_Server::CREATABLE,
|
||||
'callback' => 'fea_crear_traduccion_handle',
|
||||
'permission_callback' => 'fea_crear_traduccion_can_call',
|
||||
// Se valida después de autorizar para que las llamadas anónimas
|
||||
// obtengan 401 aunque omitan parámetros.
|
||||
'args' => [
|
||||
'es_id' => [
|
||||
'sanitize_callback' => 'absint',
|
||||
],
|
||||
'lang' => [
|
||||
'sanitize_callback' => 'sanitize_key',
|
||||
],
|
||||
'status' => [
|
||||
'sanitize_callback' => 'sanitize_key',
|
||||
],
|
||||
'model' => [
|
||||
'sanitize_callback' => 'sanitize_text_field',
|
||||
],
|
||||
],
|
||||
]);
|
||||
});
|
||||
|
||||
/** Editor o superior: mismo nivel que los demás endpoints fea/v1 de escritura. */
|
||||
function fea_crear_traduccion_can_call(WP_REST_Request $request) {
|
||||
if (!is_user_logged_in()) {
|
||||
return new WP_Error(
|
||||
'fea_crear_traduccion_not_authenticated',
|
||||
'Debes autenticarte para crear una traducción.',
|
||||
['status' => 401]
|
||||
);
|
||||
}
|
||||
if (!current_user_can('edit_others_posts')) {
|
||||
return new WP_Error(
|
||||
'fea_crear_traduccion_forbidden',
|
||||
'No tienes permiso para crear traducciones.',
|
||||
['status' => 403]
|
||||
);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
function fea_crear_traduccion_handle(WP_REST_Request $request) {
|
||||
$es_id = absint($request->get_param('es_id'));
|
||||
if (!$es_id) {
|
||||
return new WP_Error(
|
||||
'fea_crear_traduccion_invalid_source',
|
||||
'es_id es obligatorio.',
|
||||
['status' => 400]
|
||||
);
|
||||
}
|
||||
|
||||
$lang = (string) $request->get_param('lang');
|
||||
if (!in_array($lang, FEA_TRANSLATION_LANGUAGES, true)) {
|
||||
return new WP_Error(
|
||||
'fea_crear_traduccion_invalid_language',
|
||||
'lang debe ser en, fr, it o pt.',
|
||||
['status' => 400]
|
||||
);
|
||||
}
|
||||
|
||||
$status = (string) ($request->get_param('status') ?: 'draft');
|
||||
if (!in_array($status, ['draft', 'publish'], true)) {
|
||||
return new WP_Error(
|
||||
'fea_crear_traduccion_invalid_status',
|
||||
'status debe ser draft o publish.',
|
||||
['status' => 400]
|
||||
);
|
||||
}
|
||||
|
||||
$source = get_post($es_id);
|
||||
if (!$source) {
|
||||
return new WP_Error(
|
||||
'fea_crear_traduccion_source_not_found',
|
||||
'No existe el post español indicado.',
|
||||
['status' => 404]
|
||||
);
|
||||
}
|
||||
if (!function_exists('pll_get_post') || !function_exists('pll_set_post_language') || !function_exists('pll_save_post_translations')) {
|
||||
return new WP_Error(
|
||||
'fea_crear_traduccion_polylang_unavailable',
|
||||
'Polylang no está disponible.',
|
||||
['status' => 500]
|
||||
);
|
||||
}
|
||||
|
||||
// Idempotencia dura: se responde antes de interpretar un payload nuevo.
|
||||
$existing_id = (int) pll_get_post($es_id, $lang);
|
||||
if ($existing_id && !get_post($existing_id)) $existing_id = 0;
|
||||
if ($existing_id) {
|
||||
return new WP_REST_Response([
|
||||
'es_id' => $es_id,
|
||||
'lang' => $lang,
|
||||
'translation_id' => $existing_id,
|
||||
'created' => false,
|
||||
'url' => get_permalink($existing_id),
|
||||
], 200);
|
||||
}
|
||||
|
||||
$title = (string) ($request->get_param('title') ?? '');
|
||||
$new_id = wp_insert_post([
|
||||
'post_title' => wp_slash($title),
|
||||
'post_content' => wp_slash((string) ($request->get_param('content') ?? '')),
|
||||
'post_excerpt' => wp_slash((string) ($request->get_param('excerpt') ?? '')),
|
||||
'post_name' => sanitize_title($title),
|
||||
'post_status' => $status,
|
||||
'post_type' => 'post',
|
||||
'post_author' => (int) $source->post_author,
|
||||
'post_date' => $source->post_date,
|
||||
'to_ping' => '',
|
||||
'pinged' => '',
|
||||
], true);
|
||||
if (is_wp_error($new_id)) {
|
||||
return new WP_Error(
|
||||
'fea_crear_traduccion_insert_failed',
|
||||
'No se pudo crear la traducción: ' . $new_id->get_error_message(),
|
||||
['status' => 500]
|
||||
);
|
||||
}
|
||||
|
||||
// El idioma se asigna antes de mapear categorías para que Polylang admita
|
||||
// los términos traducidos en el nuevo post.
|
||||
pll_set_post_language($new_id, $lang);
|
||||
|
||||
$categories = wp_get_post_categories($es_id);
|
||||
$mapped_categories = [];
|
||||
foreach ($categories as $category_id) {
|
||||
$translated_category = function_exists('pll_get_term') ? (int) pll_get_term($category_id, $lang) : 0;
|
||||
$mapped_categories[] = $translated_category ?: $category_id;
|
||||
}
|
||||
if ($mapped_categories) {
|
||||
wp_set_post_categories($new_id, array_values(array_unique($mapped_categories)));
|
||||
}
|
||||
|
||||
$translations = function_exists('pll_get_post_translations') ? pll_get_post_translations($es_id) : ['es' => $es_id];
|
||||
if (!$translations) $translations = ['es' => $es_id];
|
||||
$translations[$lang] = $new_id;
|
||||
pll_save_post_translations($translations);
|
||||
|
||||
update_post_meta($new_id, 'traduccion_automatica', '1');
|
||||
update_post_meta($new_id, 'traduccion_origen', $es_id);
|
||||
update_post_meta($new_id, 'traduccion_modelo', (string) ($request->get_param('model') ?? ''));
|
||||
update_post_meta($new_id, 'traduccion_fecha', gmdate('c'));
|
||||
|
||||
return new WP_REST_Response([
|
||||
'es_id' => $es_id,
|
||||
'lang' => $lang,
|
||||
'translation_id' => (int) $new_id,
|
||||
'created' => true,
|
||||
'url' => get_permalink($new_id),
|
||||
], 201);
|
||||
}
|
||||
Reference in New Issue
Block a user