Files
gureametsabilagun/wp-content/mu-plugins/gure-ametsa/api.php
Josep Piguillem 1630428b46 Documentación Swagger propia: el plugin de wordpress.org no incluye la interfaz (página en blanco)
WP API SwaggerUI se sigue usando para generar el esquema OpenAPI (/rest-api/schema);
/rest-api/docs/ se sirve con Swagger UI 5.33 oficial (versión fijada, integridad SRI)
y autentica «Try it out» con la sesión de WordPress.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-25 08:44:34 +02:00

178 lines
7.2 KiB
PHP

<?php
/**
* APIs: REST (/wp-json/wp/v2/animales) y GraphQL (/graphql). Documentación Swagger protegida.
*/
defined( 'ABSPATH' ) || exit;
/** Ficha de un animal lista para las APIs: valores internos + textos legibles en su idioma. */
function ga_animal_api_data( $post_id ) {
$lang = function_exists( 'pll_get_post_language' ) ? ( pll_get_post_language( $post_id ) ?: 'es' ) : 'es';
$data = array(
'estado' => ga_status( $post_id ),
'destacado' => (bool) ga_get( $post_id, 'destacado' ),
'sexo' => ga_get( $post_id, 'sexo' ),
'nacimiento' => ga_get( $post_id, 'nacimiento' ),
'edad' => '' === ga_get( $post_id, 'edad' ) ? null : (float) ga_get( $post_id, 'edad' ),
'edad_unidad' => ga_get( $post_id, 'edad_unidad' ),
'tamano' => ga_get( $post_id, 'tamano' ),
'llegada' => ga_get( $post_id, 'llegada' ),
'galeria' => array_map( fn( $id ) => wp_get_attachment_image_url( $id, 'large' ), ga_gallery_ids( $post_id ) ),
'video' => ga_get( $post_id, 'video' ),
'caracter' => ga_get( $post_id, 'caracter' ),
'necesidades' => ga_get( $post_id, 'necesidades' ),
'convivencia' => ga_get( $post_id, 'convivencia' ),
'hogar' => ga_get( $post_id, 'hogar' ),
'idioma' => $lang,
);
$data['textos'] = ga_with_lang( $lang, fn() => array(
'estado' => ga_label( $post_id, 'estado' ),
'sexo' => ga_label( $post_id, 'sexo' ),
'edad' => ga_age( $post_id ),
'tamano' => ga_label( $post_id, 'tamano' ),
) );
return $data;
}
add_action( 'rest_api_init', function () {
register_rest_field( 'animal', 'ficha', array(
'get_callback' => fn( $post ) => ga_animal_api_data( $post['id'] ),
'schema' => array(
'description' => 'Ficha del animal (valores internos y textos legibles en su idioma).',
'type' => 'object',
'context' => array( 'view', 'edit' ),
'readonly' => true,
'properties' => array(
'estado' => array( 'type' => 'string', 'enum' => array( 'disponible', 'proceso', 'adoptado' ) ),
'destacado' => array( 'type' => 'boolean' ),
'sexo' => array( 'type' => 'string' ),
'nacimiento' => array( 'type' => 'string' ),
'edad' => array( 'type' => array( 'number', 'null' ) ),
'edad_unidad' => array( 'type' => 'string' ),
'tamano' => array( 'type' => 'string' ),
'llegada' => array( 'type' => 'string' ),
'galeria' => array( 'type' => 'array', 'items' => array( 'type' => 'string', 'format' => 'uri' ) ),
'video' => array( 'type' => 'string' ),
'caracter' => array( 'type' => 'string' ),
'necesidades' => array( 'type' => 'string' ),
'convivencia' => array( 'type' => 'string' ),
'hogar' => array( 'type' => 'string' ),
'idioma' => array( 'type' => 'string' ),
'textos' => array( 'type' => 'object' ),
),
),
) );
} );
add_action( 'graphql_register_types', function () {
register_graphql_object_type( 'AnimalFichaTextos', array(
'description' => 'Textos legibles de la ficha, en el idioma del animal.',
'fields' => array(
'estado' => array( 'type' => 'String' ),
'sexo' => array( 'type' => 'String' ),
'edad' => array( 'type' => 'String' ),
'tamano' => array( 'type' => 'String' ),
),
) );
register_graphql_object_type( 'AnimalFicha', array(
'description' => 'Ficha del animal en adopción.',
'fields' => array(
'estado' => array( 'type' => 'String', 'description' => 'disponible, proceso o adoptado' ),
'destacado' => array( 'type' => 'Boolean' ),
'sexo' => array( 'type' => 'String' ),
'nacimiento' => array( 'type' => 'String' ),
'edad' => array( 'type' => 'Float' ),
'edadUnidad' => array( 'type' => 'String' ),
'tamano' => array( 'type' => 'String' ),
'llegada' => array( 'type' => 'String' ),
'galeria' => array( 'type' => array( 'list_of' => 'String' ) ),
'video' => array( 'type' => 'String' ),
'caracter' => array( 'type' => 'String' ),
'necesidades' => array( 'type' => 'String' ),
'convivencia' => array( 'type' => 'String' ),
'hogar' => array( 'type' => 'String' ),
'idioma' => array( 'type' => 'String' ),
'textos' => array( 'type' => 'AnimalFichaTextos' ),
),
) );
register_graphql_field( 'Animal', 'ficha', array(
'type' => 'AnimalFicha',
'resolve' => function ( $post ) {
$data = ga_animal_api_data( $post->databaseId );
$data['edadUnidad'] = $data['edad_unidad'];
return $data;
},
) );
} );
/*
* Documentación Swagger (/rest-api/docs/).
*
* El plugin WP API SwaggerUI genera bien el esquema OpenAPI (/rest-api/schema), pero su paquete
* en wordpress.org no incluye los archivos de la interfaz (assets/), así que su página sale en blanco.
* Servimos nuestra propia página con Swagger UI oficial (versión fijada y con integridad SRI).
* Solo para usuarios conectados, salvo API_DOCS_PUBLIC=true.
*/
define( 'GA_SWAGGER_UI_VERSION', '5.33.0' );
add_action( 'template_redirect', function () {
if ( 'docs' !== get_query_var( 'swagger_api' ) ) {
return;
}
if ( 'true' !== getenv( 'API_DOCS_PUBLIC' ) && ! is_user_logged_in() ) {
auth_redirect();
}
$cdn = 'https://cdn.jsdelivr.net/npm/swagger-ui-dist@' . GA_SWAGGER_UI_VERSION;
$config = array(
'url' => home_url( '/rest-api/schema' ),
'nonce' => is_user_logged_in() ? wp_create_nonce( 'wp_rest' ) : '',
);
nocache_headers();
header( 'Content-Type: text/html; charset=utf-8' );
?>
<!doctype html>
<html lang="es">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="robots" content="noindex">
<title><?php echo esc_html( get_bloginfo( 'name' ) ); ?> · API</title>
<link rel="stylesheet" href="<?php echo esc_url( $cdn . '/swagger-ui.css' ); ?>" integrity="sha384-Ov4/wv3j2bmct8cDc5X4ngJZohVPzEmc6uDPH8WeljUxO5vtoykvMEfbu9Vh6RaW" crossorigin="anonymous">
<style>body{margin:0;background:#fafafa}.ga-api-bar{padding:10px 20px;background:#401f0c;color:#fff;font:14px system-ui,sans-serif}.ga-api-bar a{color:#e6d9b7}</style>
</head>
<body>
<div class="ga-api-bar">
<?php echo esc_html( get_bloginfo( 'name' ) ); ?> · API REST ·
<a href="<?php echo esc_url( home_url( '/rest-api/schema' ) ); ?>">Esquema OpenAPI</a> ·
<a href="<?php echo esc_url( home_url( '/graphql' ) ); ?>">GraphQL</a> ·
<a href="<?php echo esc_url( admin_url() ); ?>">Volver al panel</a>
</div>
<div id="swagger-ui"></div>
<script src="<?php echo esc_url( $cdn . '/swagger-ui-bundle.js' ); ?>" integrity="sha384-YDALVcy8kj8yltLBVi1vBiBAUqdxvus673gM8XKwiy6aDUJFXivF/KCufekjYbVf" crossorigin="anonymous"></script>
<script>
( function ( config ) {
window.ui = SwaggerUIBundle( {
url: config.url,
dom_id: '#swagger-ui',
deepLinking: true,
docExpansion: 'none',
filter: true,
tryItOutEnabled: false,
// Con la sesión iniciada, «Try it out» se autentica con la cookie + nonce de WordPress.
requestInterceptor: function ( req ) {
if ( config.nonce && req.url.indexOf( '/wp-json/' ) !== -1 ) {
req.headers[ 'X-WP-Nonce' ] = config.nonce;
req.credentials = 'same-origin';
}
return req;
}
} );
} )( <?php echo wp_json_encode( $config ); ?> );
</script>
</body>
</html>
<?php
exit;
}, 1 );