From 532bc620dea03d7dbb2fdb9552c4347875357361 Mon Sep 17 00:00:00 2001 From: Josep Date: Thu, 24 Sep 2026 17:22:46 +0200 Subject: [PATCH] change logo and colors --- .env.example | 4 + README.md | 41 +++++- docker-compose.yml | 1 + docker/setup.sh | 13 ++ wp-content/mu-plugins/gure-ametsa-core.php | 130 ++++++++++++++++++ .../themes/gure-ametsa/assets/img/favicon.svg | 5 +- .../gure-ametsa/assets/img/logo-mark.svg | 4 + .../themes/gure-ametsa/assets/img/logo.svg | 5 + wp-content/themes/gure-ametsa/footer.php | 2 +- wp-content/themes/gure-ametsa/functions.php | 38 ++++- .../themes/gure-ametsa/inc/registry.php | 17 ++- wp-content/themes/gure-ametsa/style.css | 17 ++- .../gure-ametsa/template-parts/home/hero.php | 2 +- 13 files changed, 263 insertions(+), 16 deletions(-) create mode 100644 wp-content/themes/gure-ametsa/assets/img/logo-mark.svg create mode 100644 wp-content/themes/gure-ametsa/assets/img/logo.svg diff --git a/.env.example b/.env.example index 227805d..7e99d08 100644 --- a/.env.example +++ b/.env.example @@ -27,5 +27,9 @@ DB_PASSWORD=cambia-esto DB_ROOT_PASSWORD=cambia-esto-tambien DB_TABLE_PREFIX=ga_ +# APIs: GraphQL en /graphql y REST en /wp-json/wp/v2/. +# true = la documentación Swagger (/rest-api/docs/) es pública; false = solo usuarios conectados +API_DOCS_PUBLIC=false + # true = crea 4 animales de ejemplo en la primera instalación (útil para probar) SEED_DEMO_ANIMALS=false diff --git a/README.md b/README.md index 859d9f1..0852d62 100644 --- a/README.md +++ b/README.md @@ -19,11 +19,50 @@ Web de la protectora **Gure Ametsa Bi Lagun** (Jaizubia 44, Hondarribia), en cas - Formulario de contacto/adopción `[ga_contacto]`. Envía un email **y** guarda cada mensaje en *Mensajes* dentro del panel, así no se pierde aunque falle el correo. - Shortcode `[ga_animales numero="6" especie="perro" estado="urgente"]` para usar en cualquier página. +## Logo y colores + +- El logo original se ha vectorizado en `wp-content/themes/gure-ametsa/assets/img/`: + - `logo.svg`: logo completo, sin fondo. + - `logo-mark.svg`: el arco con el perro y el gato, sin texto. + - `favicon.svg`: el mismo símbolo, para la pestaña del navegador. +- Las capas del SVG (arco, animales, texto) llevan clases propias. Así, en el pie oscuro el texto del logo se muestra en beige. +- La paleta por defecto, «Colores del logo», sale del propio logo: + + | Color | Valor | Dónde se usa | + |---|---|---| + | Principal | `#401f0c` (marrón del logo) | Cabecera, botones, secciones oscuras | + | Acento | `#bd8537` (caramelo, el beige del logo más intenso) | Botones principales y palabras resaltadas | + | Secciones | `#f3ecdc` (beige aclarado) | Fondos alternos | + | Fondo | `#fcfaf5` | Fondo general | + | Texto | `#2b1508` | Texto | + +- En *Diseño → Cabecera* se elige cómo sale el logo arriba: símbolo + nombre, logo completo o solo el nombre. + +## APIs + +| API | Dirección | Qué incluye | +|---|---|---| +| REST | `/wp-json/wp/v2/animales`, `/wp-json/wp/v2/especies` | Animales con el campo `ficha` (valores y textos legibles en su idioma). Se puede filtrar por idioma con `?lang=es` o `?lang=eu`. | +| GraphQL (WPGraphQL) | `/graphql` | Tipos `Animal` / `Especie` con el campo `ficha`. Explorador GraphiQL en el panel (menú GraphQL). | +| Swagger / OpenAPI 3 | `/rest-api/docs/` (interfaz) y `/rest-api/schema` (esquema) | Documentación interactiva de la API REST. Por defecto solo para usuarios conectados; `API_DOCS_PUBLIC=true` la hace pública. | + +Ejemplo de consulta GraphQL: + +```graphql +{ + animales(first: 10) { + nodes { title uri especies { nodes { name } } ficha { estado edad edadUnidad compatible textos { estado edad } } } + } +} +``` + +Para escribir en la API REST (crear o editar animales) se usan las *contraseñas de aplicación* de WordPress (Usuarios → Perfil) con autenticación Basic sobre HTTPS; Swagger lo admite desde el botón «Authorize». Los mensajes del formulario no se exponen en ninguna API. + ## Diseño El diseño está inspirado en [Beargrass Animal Rescue](https://louisvillewebguy.com/examples/beargrass-animal-rescue/): - **Tipografía:** títulos en Fraunces muy gruesa y texto en Karla. Las dos van incluidas en el tema, sin Google Fonts. -- **Paleta por defecto:** ciruela y mostaza. +- **Paletas:** por defecto, los colores del logo. También están ciruela y mostaza (la de Beargrass), verde y rojo, azul mar y bosque. - **Portada:** a pantalla completa con cuatro «puertas»: Adopta, Acoge, Voluntariado y Dona. - **Listado de animales:** panel de filtros por especie, tamaño, edad, sexo y compatibilidad. - **Pasos de adopción:** en tarjetas. diff --git a/docker-compose.yml b/docker-compose.yml index 05f23a1..0a9b90e 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -28,6 +28,7 @@ services: WP_ADMIN_EMAIL: ${WP_ADMIN_EMAIL:?Define WP_ADMIN_EMAIL} GA_CONTACT_EMAIL: ${GA_CONTACT_EMAIL:-hola@gureametsabilagun.org} SEED_DEMO_ANIMALS: ${SEED_DEMO_ANIMALS:-false} + API_DOCS_PUBLIC: ${API_DOCS_PUBLIC:-false} SMTP_HOST: ${SMTP_HOST:-} SMTP_PORT: ${SMTP_PORT:-587} SMTP_ENCRYPTION: ${SMTP_ENCRYPTION:-tls} diff --git a/docker/setup.sh b/docker/setup.sh index 815d2a4..d29e258 100644 --- a/docker/setup.sh +++ b/docker/setup.sh @@ -157,4 +157,17 @@ if (( VERSION < 3 )); then wp_ option update ga_setup_version 3 fi +# Etapa 4: APIs (GraphQL y documentación Swagger de la API REST) +if (( VERSION < 4 )); then + log "Instalando APIs: WPGraphQL y Swagger" + for plugin in wp-graphql wp-api-swaggerui; do + wp_ plugin install "$plugin" --activate >/dev/null 2>&1 && log " ✓ $plugin" || log " ✗ No se pudo instalar $plugin" + done + wp_ option update swagger_api_spec_version 3.0.3 # OpenAPI 3 + wp_ option update swagger_api_expose_contact_email 0 # no publicar el email del administrador + wp_ option update swagger_api_basepath /wp/v2 + wp_ rewrite flush + wp_ option update ga_setup_version 4 +fi + log "Configuración completada" diff --git a/wp-content/mu-plugins/gure-ametsa-core.php b/wp-content/mu-plugins/gure-ametsa-core.php index 981d57c..95cfcc5 100644 --- a/wp-content/mu-plugins/gure-ametsa-core.php +++ b/wp-content/mu-plugins/gure-ametsa-core.php @@ -14,6 +14,9 @@ defined( 'ABSPATH' ) || exit; /** Idioma actual: 'es' o 'eu'. El panel de administración siempre en castellano. */ function ga_lang() { + if ( isset( $GLOBALS['ga_forced_lang'] ) ) { + return 'eu' === $GLOBALS['ga_forced_lang'] ? 'eu' : 'es'; + } if ( is_admin() && ! wp_doing_ajax() ) { return 'es'; } @@ -108,6 +111,11 @@ add_action( 'init', function () { 'menu_position' => 5, 'supports' => array( 'title', 'editor', 'thumbnail', 'excerpt' ), 'show_in_rest' => true, + 'rest_base' => 'animales', + // WPGraphQL + 'show_in_graphql' => true, + 'graphql_single_name' => 'animal', + 'graphql_plural_name' => 'animales', ) ); register_taxonomy( 'especie', 'animal', array( @@ -119,6 +127,10 @@ add_action( 'init', function () { 'hierarchical' => true, 'show_admin_column' => true, 'show_in_rest' => true, + 'rest_base' => 'especies', + 'show_in_graphql' => true, + 'graphql_single_name' => 'especie', + 'graphql_plural_name' => 'especies', 'rewrite' => array( 'slug' => 'especie', 'with_front' => false ), ) ); @@ -632,3 +644,121 @@ function ga_handle_contact() { $go( 'ok' ); } + +/* ------------------------------------------------------------------------- + * APIs: REST (/wp-json/wp/v2/animales) y GraphQL (/graphql) + * ---------------------------------------------------------------------- */ + +/** Ficha de un animal lista para las APIs: valores internos + textos legibles. */ +function ga_animal_api_data( $post_id ) { + $lang = function_exists( 'pll_get_post_language' ) ? ( pll_get_post_language( $post_id ) ?: 'es' ) : 'es'; + $list = fn( $key ) => array_values( array_filter( explode( ',', ga_get( $post_id, $key ) ) ) ); + $data = array( + 'estado' => ga_get( $post_id, 'estado' ) ?: 'disponible', + 'sexo' => ga_get( $post_id, 'sexo' ), + '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' ), + 'raza' => ga_get( $post_id, 'raza' ), + 'llegada' => ga_get( $post_id, 'llegada' ), + 'salud' => $list( 'salud' ), + 'compatible' => $list( 'compatible' ), + 'idioma' => $lang, + ); + // Textos legibles en el idioma del animal. + $labels = function () use ( $post_id ) { + return array( + 'estado' => ga_label( $post_id, 'estado' ) ?: ga__( 'En adopción', 'Adopzioan' ), + 'sexo' => ga_label( $post_id, 'sexo' ), + 'edad' => ga_age( $post_id ), + 'tamano' => ga_label( $post_id, 'tamano' ), + 'salud' => ga_label( $post_id, 'salud' ) ?: array(), + 'compatible' => ga_label( $post_id, 'compatible' ) ?: array(), + ); + }; + $data['textos'] = ga_with_lang( $lang, $labels ); + return $data; +} + +/** Ejecuta $callback como si el idioma actual fuera $lang (para las etiquetas). */ +function ga_with_lang( $lang, callable $callback ) { + $GLOBALS['ga_forced_lang'] = $lang; + try { + return $callback(); + } finally { + unset( $GLOBALS['ga_forced_lang'] ); + } +} + +/* REST: campo «ficha» de solo lectura en /wp/v2/animales */ +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', 'urgente', 'acogida', 'reservado', 'adoptado' ) ), + 'sexo' => array( 'type' => 'string' ), + 'edad' => array( 'type' => array( 'number', 'null' ) ), + 'edad_unidad' => array( 'type' => 'string', 'enum' => array( '', 'anos', 'meses' ) ), + 'tamano' => array( 'type' => 'string' ), + 'raza' => array( 'type' => 'string' ), + 'llegada' => array( 'type' => 'string', 'format' => 'date' ), + 'salud' => array( 'type' => 'array', 'items' => array( 'type' => 'string' ) ), + 'compatible' => array( 'type' => 'array', 'items' => array( 'type' => 'string' ) ), + 'idioma' => array( 'type' => 'string' ), + 'textos' => array( 'type' => 'object' ), + ), + ), + ) ); +} ); + +/* GraphQL: tipo AnimalFicha y campo «ficha» en Animal */ +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' ), + 'salud' => array( 'type' => array( 'list_of' => 'String' ) ), + 'compatible' => array( 'type' => array( 'list_of' => 'String' ) ), + ), + ) ); + register_graphql_object_type( 'AnimalFicha', array( + 'description' => 'Ficha del animal en adopción.', + 'fields' => array( + 'estado' => array( 'type' => 'String', 'description' => 'disponible, urgente, acogida, reservado o adoptado' ), + 'sexo' => array( 'type' => 'String' ), + 'edad' => array( 'type' => 'Float' ), + 'edadUnidad' => array( 'type' => 'String', 'description' => 'anos o meses' ), + 'tamano' => array( 'type' => 'String' ), + 'raza' => array( 'type' => 'String' ), + 'llegada' => array( 'type' => 'String' ), + 'salud' => array( 'type' => array( 'list_of' => 'String' ) ), + 'compatible' => array( 'type' => array( 'list_of' => '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/): solo para usuarios conectados, salvo API_DOCS_PUBLIC=true */ +add_action( 'template_redirect', function () { + if ( 'docs' === get_query_var( 'swagger_api' ) && 'true' !== getenv( 'API_DOCS_PUBLIC' ) && ! is_user_logged_in() ) { + auth_redirect(); + } +}, 1 ); + diff --git a/wp-content/themes/gure-ametsa/assets/img/favicon.svg b/wp-content/themes/gure-ametsa/assets/img/favicon.svg index 3a7c78f..86d3584 100644 --- a/wp-content/themes/gure-ametsa/assets/img/favicon.svg +++ b/wp-content/themes/gure-ametsa/assets/img/favicon.svg @@ -1 +1,4 @@ - + + + + diff --git a/wp-content/themes/gure-ametsa/assets/img/logo-mark.svg b/wp-content/themes/gure-ametsa/assets/img/logo-mark.svg new file mode 100644 index 0000000..f9f826d --- /dev/null +++ b/wp-content/themes/gure-ametsa/assets/img/logo-mark.svg @@ -0,0 +1,4 @@ + diff --git a/wp-content/themes/gure-ametsa/assets/img/logo.svg b/wp-content/themes/gure-ametsa/assets/img/logo.svg new file mode 100644 index 0000000..bbe73d4 --- /dev/null +++ b/wp-content/themes/gure-ametsa/assets/img/logo.svg @@ -0,0 +1,5 @@ + diff --git a/wp-content/themes/gure-ametsa/footer.php b/wp-content/themes/gure-ametsa/footer.php index 8e2fee6..6ba1660 100644 --- a/wp-content/themes/gure-ametsa/footer.php +++ b/wp-content/themes/gure-ametsa/footer.php @@ -21,7 +21,7 @@ $columns = array(
- +