diff --git a/README.md b/README.md index 0852d62..8c0067c 100644 --- a/README.md +++ b/README.md @@ -19,6 +19,36 @@ 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. +## Gestión del día a día (sin tocar código) + +| Qué | Dónde | +|---|---| +| Añadir o editar un animal | **Animales → Añadir animal**. Arriba va la historia y debajo la ficha:
• Datos comunes a castellano y euskera: estado, destacado, sexo, nacimiento o edad aproximada, tamaño, fecha de entrada, más fotos y vídeo.
• Textos de cada idioma: cómo es, qué necesita, convivencia y el hogar que buscamos.
La versión en euskera se crea con el **+** de la caja «Idiomas»; los datos comunes y las fotos se copian solos. | +| Estado | *Disponible*, *En proceso* o *Adoptado*. Los adoptados salen solos del listado. | +| Animales de la portada | Marcar **Destacado** en su ficha. Si no hay ninguno, salen los que llevan más tiempo. | +| Ayuda material | **Personalizar → Adopción y colabora → Ayuda material** (una línea por necesidad). | +| Textos del botón «Quiero conocerlo/la», formulario, confirmación, proceso, correo de destino | **Personalizar → Adopción y colabora → Listado y fichas**. | +| Aviso de cita previa, teléfono, horario | **Personalizar → Contacto y redes**. | +| Portada | **Personalizar → Portada**: cada bloque se puede mostrar u ocultar y reordenar. Por defecto se ve: portada principal, animales destacados, acogida, quiénes somos y contacto. Donaciones, cifras, finales felices, etc. están ocultos. | +| Menú | **Apariencia → Menús** (Principal / Nagusia). | +| Páginas (Acoge, Colabora, Quiénes somos, Contacto, Preguntas frecuentes) | **Páginas**, con el editor de bloques y los patrones «Gure Ametsa». | +| Mensajes recibidos | Menú **Mensajes** (además llegan por correo). | + +Cada ficha tiene su propio enlace y botones para compartirla por WhatsApp o Facebook, o copiar el enlace. + +## Migraciones + +`docker/setup.sh` se ejecuta en cada arranque y aplica por etapas lo que falte (`ga_setup_version`): + +| Etapa | Qué hace | +|---|---| +| 2 | Idiomas, tema, páginas y menús iniciales | +| 3 | Plugins recomendados | +| 4 | APIs (WPGraphQL, Swagger) | +| 5 | Indicaciones del cliente: páginas Acoge y Preguntas frecuentes, menú con submenús, retirada del hotel, estados nuevos y sin animaciones | + +`docker/setup-content.php` es idempotente. **Las páginas que el cliente haya editado nunca se sobrescriben**; se detecta con una huella del contenido original. + ## Logo y colores - El logo original se ha vectorizado en `wp-content/themes/gure-ametsa/assets/img/`: @@ -63,8 +93,8 @@ Para escribir en la API REST (crear o editar animales) se usan las *contraseñas 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. - **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. +- **Portada:** a pantalla completa, con foto real y botones a perros y gatos. +- **Listado de animales:** solo Perros y Gatos, con tarjetas de foto y nombre, sin filtros ni etiquetas, a petición del cliente. - **Pasos de adopción:** en tarjetas. - **Contacto:** sección oscura con el formulario en una tarjeta. - **Pie:** columnas de enlaces. @@ -128,7 +158,6 @@ Se instalan solos en el primer arranque (etapa 3 de `docker/setup.sh`). | Smash Balloon Instagram Feed | activo | Muestra vuestro Instagram. Hay que conectar la cuenta. | | Koko Analytics | activo | Estadísticas de visitas sin cookies. | | Kadence Blocks | activo | Bloques visuales extra: carruseles de imágenes, pestañas, acordeones e iconos. | -| Blocks Animation | activo | Animaciones de entrada para cualquier bloque. | | GiveWP | desactivado | Donaciones online con tarjeta o PayPal. | | MailPoet | desactivado | Newsletter. | | Complianz | desactivado | Aviso de cookies. Solo hace falta si añadís YouTube, Analytics, etc. | diff --git a/docker/content/es/acoge.html b/docker/content/es/acoge.html new file mode 100644 index 0000000..08d8b2a --- /dev/null +++ b/docker/content/es/acoge.html @@ -0,0 +1,29 @@ + +

Quizá ahora no puedas adoptar, pero sí ofrecer un hogar durante un tiempo. Escríbenos y te contamos qué animales necesitan acogida y cómo puedes ayudar.

+ + + +

¿Qué es una casa de acogida?

+ + + +

Es un hogar temporal para un perro o un gato mientras encuentra a su familia. Algunos lo necesitan especialmente: cachorros, animales mayores o que se están recuperando y que están mejor en una casa que en la protectora.

+ + + +

¿Qué supone?

+ + + +

Cada acogida es distinta. Antes de empezar hablamos contigo de cuánto tiempo sería, los gastos, el material que hace falta y cómo te acompañamos durante la acogida.

+ + + +
+
Quiero ser casa de acogida
+
+ + + +

¿Tienes dudas? Mira las preguntas frecuentes o escríbenos.

+ diff --git a/docker/content/es/colabora.html b/docker/content/es/colabora.html index 5cdf1ca..100643a 100644 --- a/docker/content/es/colabora.html +++ b/docker/content/es/colabora.html @@ -1,63 +1,45 @@ -

Cada ayuda cuenta. Estas son las formas en las que puedes cambiar la vida de nuestros animales:

- - - -

🏡 Adopta

- - - -

Adoptar es la forma más directa de salvar una vida. Consulta los animales en adopción, ven a conocerlos y te acompañaremos en todo el proceso. Todos se entregan con microchip, vacunados y esterilizados.

- - - -

🤝 Casa de acogida

- - - -

Algunos animales necesitan salir del centro cuanto antes: cachorros, mayores o convalecientes. Como casa de acogida les ofreces un hogar temporal mientras encuentran su familia definitiva. Nosotros te orientamos en todo momento.

+

Hay muchas maneras de ayudar a los animales de Bilagun, y todas cuentan.

-

🦮 Voluntariado

+

Voluntariado

-

Pasear perros, socializar gatos, ayudar en jornadas de adopción, hacer fotos para las fichas o difundir en redes sociales. Si tienes tiempo y ganas, ¡te necesitamos!

- - - -

💚 Donaciones

- - - -

Siempre nos vienen bien:

- - - - - - - -

Si prefieres hacer una aportación económica, escríbenos y te indicamos cómo.

+

Paseos, compañía y socialización de perros y gatos. Si te apetece echarnos una mano, concertamos una primera cita y rellenamos juntos un cuestionario.

-
Quiero colaborar
+
Quiero ser voluntario
+
+ + + +

Ayuda material

+ + + +[ga_necesidades] + + + +
+
Escríbenos
+
+ + + +

Comparte sus historias

+ + + +

Si no puedes adoptar, también puedes ayudar compartiendo su historia. Cada ficha tiene su propio enlace para enviarla por WhatsApp o redes.

+ + + +
+
Ver los animales
diff --git a/docker/content/es/contacto.html b/docker/content/es/contacto.html index 1372b74..62dab77 100644 --- a/docker/content/es/contacto.html +++ b/docker/content/es/contacto.html @@ -1,5 +1,9 @@ + +[ga_cita] + + -

📍 Jaizubia, 44 · 20280 Hondarribia (Gipuzkoa)
📞 943 64 52 79
✉️ hola@gureametsabilagun.org
🕙 Lunes a viernes: 10:00–13:00 y 14:00–19:00

+

Jaizubia, 44 · 20280 Hondarribia (Gipuzkoa)
943 64 52 79 · hola@gureametsabilagun.org
Atención al público: lunes a viernes, 10:00–13:00 y 14:00–19:00

@@ -7,7 +11,7 @@ -

Para adopciones, acogidas, voluntariado o reservas del hotel, déjanos tu mensaje y te responderemos lo antes posible.

+

Cuéntanos qué necesitas y te respondemos lo antes posible.

diff --git a/docker/content/es/hotel.html b/docker/content/es/hotel.html deleted file mode 100644 index 7f934c9..0000000 --- a/docker/content/es/hotel.html +++ /dev/null @@ -1,35 +0,0 @@ - -

¿Planeas unas vacaciones y no puedes llevar a tu compañero? En Gure Ametsa Bi Lagun cuidamos de tu perro o gato mientras estás fuera, en nuestras instalaciones de Jaizubia (Hondarribia), rodeadas de naturaleza.

- - - -

Qué ofrecemos

- - - - - - - -

Para reservar es necesario que el animal tenga el microchip y las vacunas al día. Las plazas se llenan en verano y fechas señaladas: reserva con antelación.

- - - -
-
Consultar disponibilidad
- - - -
Llamar: 943 64 52 79
-
- diff --git a/docker/content/es/preguntas-frecuentes.html b/docker/content/es/preguntas-frecuentes.html new file mode 100644 index 0000000..e685634 --- /dev/null +++ b/docker/content/es/preguntas-frecuentes.html @@ -0,0 +1,39 @@ + +
¿Cómo puedo adoptar? +

Entra en la ficha del animal que te interese y pulsa «Quiero conocerlo» o «Quiero conocerla». Te enviaremos nuestro cuestionario, lo valoramos con el equipo y quedamos para conoceros. Enviar la solicitud no confirma una adopción.

+
+ + + +
¿Puedo ir directamente a conocer a los animales? +

Las visitas son siempre con cita previa. Escríbenos o llámanos y buscamos un momento.

+
+ + + +
¿Qué supone una acogida? +

Ofrecer un hogar temporal a un animal mientras encuentra a su familia. La duración, los gastos, el material y el acompañamiento los concretamos contigo en cada caso.

+
+ + + +
¿Cómo puedo hacer voluntariado? +

Escríbenos: concertamos una primera cita y rellenamos un cuestionario. Buscamos ayuda con paseos, compañía y socialización.

+
+ + + +
¿Qué material necesitáis? +

Tienes la lista actualizada en Colabora. Antes de traer nada, escríbenos para concretar la entrega.

+
+ + + +
¿Puedo adoptar si ya tengo otros animales? +

Depende de cada caso. Cuéntanoslo cuando nos escribas y lo valoramos juntos con el equipo.

+
+ + + +

¿No encuentras tu respuesta? Escríbenos.

+ diff --git a/docker/content/es/quienes-somos.html b/docker/content/es/quienes-somos.html index 1a9f132..ea79d09 100644 --- a/docker/content/es/quienes-somos.html +++ b/docker/content/es/quienes-somos.html @@ -1,43 +1,33 @@ -

Gure Ametsa Bi Lagun (en euskera, «nuestro sueño, dos amigos») es un centro de protección y residencia de animales situado en Jaizubia, Hondarribia.

+

Bilagun es la protectora de Jaizubia, en Hondarribia. Desde hace más de 25 años colaboramos con los ayuntamientos de Irun y Hondarribia: cuando aparece un perro o un gato perdido o abandonado, llega a nuestras instalaciones, pasa control veterinario y lo cuidamos hasta que vuelve con su familia o encuentra una nueva.

-

Nuestra labor

+

Cómo los cuidamos

-

Trabajamos desde hace más de 25 años con los ayuntamientos de Irun y Hondarribia. Cuando la Policía Municipal encuentra un animal perdido o abandonado en la vía pública, lo trae a nuestras instalaciones. Aquí pasa un control veterinario y permanece alojado y cuidado hasta que vuelve con su familia o encuentra una nueva.

+

Para nosotras cada animal es un individuo, con su historia, sus miedos y su forma de ser. Intentamos conocerlo bien para contar con sinceridad cómo es y qué necesita.

-

Cumpliendo la Ley de Bienestar Animal, todos los animales reciben los tratamientos necesarios antes de ser adoptados:

+

Antes de la adopción, todos reciben microchip, vacunas, desparasitación y esterilización.

- - - - - -
-

Adopta y cambia dos mundos: el suyo y el tuyo.

-
- - -

¿Has perdido a tu animal?

+

Qué buscamos para ellos

-

Si has perdido a tu perro o gato en Irun u Hondarribia, llámanos cuanto antes al 943 64 52 79 y avisa también a la Policía Municipal. Tener el microchip actualizado es la mejor forma de que vuelva a casa.

+

No buscamos familias perfectas, sino familias que encajen con cada animal y respeten su ritmo. Por eso vamos sin prisas: primero nos conocemos y después valoramos juntos.

+ + +
+
Conoce a los animales
+ + + +
Colabora
+
+ diff --git a/docker/content/eu/harremanetarako.html b/docker/content/eu/harremanetarako.html index 031503d..d741221 100644 --- a/docker/content/eu/harremanetarako.html +++ b/docker/content/eu/harremanetarako.html @@ -1,5 +1,9 @@ + +[ga_cita] + + -

📍 Jaizubia, 44 · 20280 Hondarribia (Gipuzkoa)
📞 943 64 52 79
✉️ hola@gureametsabilagun.org
🕙 Astelehenetik ostiralera: 10:00–13:00 eta 14:00–19:00

+

Jaizubia, 44 · 20280 Hondarribia (Gipuzkoa)
943 64 52 79 · hola@gureametsabilagun.org
Jendaurreko arreta: astelehenetik ostiralera, 10:00–13:00 eta 14:00–19:00

@@ -7,7 +11,7 @@ -

Adopzioak, harrerak, boluntariotza edo hoteleko erreserbak direla eta, utzi zure mezua eta ahalik eta lasterren erantzungo dizugu.

+

Kontaiguzu zer behar duzun eta ahalik eta lasterren erantzungo dizugu.

diff --git a/docker/content/eu/harrera.html b/docker/content/eu/harrera.html new file mode 100644 index 0000000..68f2336 --- /dev/null +++ b/docker/content/eu/harrera.html @@ -0,0 +1,29 @@ + +

Agian orain ezin duzu adoptatu, baina bai etxe bat eskaini denbora batez. Idatzi iezaguzu eta kontatuko dizugu zein animaliak behar duten harrera eta nola lagun dezakezun.

+ + + +

Zer da harrera-etxe bat?

+ + + +

Txakur edo katu batentzako aldi baterako etxea da, bere familia aurkitu bitartean. Batzuek bereziki behar dute: kumeek, animalia zaharrek edo sendatzen ari direnek, babeslekuan baino hobeto baitaude etxe batean.

+ + + +

Zer dakar?

+ + + +

Harrera bakoitza desberdina da. Hasi aurretik zurekin hitz egingo dugu iraupenaz, gastuez, behar den materialaz eta harreran zehar nola lagunduko dizugun.

+ + + +
+
Harrera-etxe izan nahi dut
+
+ + + +

Zalantzarik baduzu? Begiratu ohiko galderak edo idatzi iezaguzu.

+ diff --git a/docker/content/eu/hotela.html b/docker/content/eu/hotela.html deleted file mode 100644 index 8d3d0b6..0000000 --- a/docker/content/eu/hotela.html +++ /dev/null @@ -1,35 +0,0 @@ - -

Oporretara joateko asmoa duzu eta ezin duzu zure laguna eraman? Gure Ametsa Bi Lagunen zure txakurra edo katua zaintzen dugu kanpoan zauden bitartean, Hondarribiko Jaizubian ditugun instalazioetan, naturaz inguratuta.

- - - -

Zer eskaintzen dugu

- - - - - - - -

Erreserba egiteko, animaliak mikrotxipa eta txertoak egunean izan behar ditu. Udan eta data berezietan plazak azkar betetzen dira: egin erreserba aldez aurretik.

- - - -
-
Galdetu erabilgarritasuna
- - - -
Deitu: 943 64 52 79
-
- diff --git a/docker/content/eu/lagundu.html b/docker/content/eu/lagundu.html index bf67763..9c861d3 100644 --- a/docker/content/eu/lagundu.html +++ b/docker/content/eu/lagundu.html @@ -1,63 +1,45 @@ -

Laguntza oro da garrantzitsua. Hauek dira gure animalien bizitza aldatzeko moduak:

- - - -

🏡 Adoptatu

- - - -

Adoptatzea da bizitza bat salbatzeko modurik zuzenena. Begiratu adopzioko animaliak, etorri haiek ezagutzera eta prozesu osoan lagunduko dizugu. Guztiak mikrotxiparekin, txertatuta eta antzututa ematen dira.

- - - -

🤝 Harrera-etxea

- - - -

Animalia batzuek lehenbailehen irten behar dute zentrotik: kumeek, zaharrek edo gaixorik daudenek. Harrera-etxe gisa, aldi baterako etxe bat eskaintzen diezu behin betiko familia aurkitu bitartean. Guk uneoro bideratuko zaitugu.

+

Bilaguneko animaliei laguntzeko modu asko daude, eta guztiak dira garrantzitsuak.

-

🦮 Boluntariotza

+

Boluntariotza

-

Txakurrak paseatu, katuak sozializatu, adopzio-jardunaldietan lagundu, fitxetarako argazkiak atera edo sare sozialetan zabaldu. Denbora eta gogoa badituzu, behar zaitugu!

- - - -

💚 Dohaintzak

- - - -

Beti ondo etortzen zaizkigu:

- - - - - - - -

Diru-ekarpen bat egin nahi baduzu, idatzi iezaguzu eta nola egin azalduko dizugu.

+

Txakur eta katuekin ibilaldiak, konpainia eta sozializazioa. Esku bat eman nahi badiguzu, lehen hitzordu bat hitzartu eta galdetegi bat beteko dugu elkarrekin.

-
Lagundu nahi dut
+
Boluntario izan nahi dut
+
+ + + +

Laguntza materiala

+ + + +[ga_necesidades] + + + +
+
Idatzi iezaguzu
+
+ + + +

Partekatu haien istorioak

+ + + +

Ezin baduzu adoptatu, haren istorioa partekatuz ere lagun dezakezu. Fitxa bakoitzak bere esteka du WhatsApp edo sare sozialen bidez bidaltzeko.

+ + + +
+
Ikusi animaliak
diff --git a/docker/content/eu/nor-gara.html b/docker/content/eu/nor-gara.html index 2a0f567..d04b461 100644 --- a/docker/content/eu/nor-gara.html +++ b/docker/content/eu/nor-gara.html @@ -1,43 +1,33 @@ -

Gure Ametsa Bi Lagun animaliak babesteko zentro eta egoitza bat da, Hondarribiko Jaizubia auzoan.

+

Bilagun Jaizubiko babeslekua da, Hondarribian. 25 urte baino gehiago daramatzagu Irun eta Hondarribiko udalekin lanean: txakur edo katu bat galduta edo abandonatuta agertzen denean, gure instalazioetara iristen da, albaitari-kontrola egiten zaio eta zaindu egiten dugu bere familiarengana itzuli arte edo familia berri bat aurkitu arte.

-

Gure lana

+

Nola zaintzen ditugun

-

25 urte baino gehiago daramatzagu Irun eta Hondarribiko udalekin lanean. Udaltzaingoak kalean galdutako edo abandonatutako animalia bat aurkitzen duenean, gure instalazioetara ekartzen du. Hemen albaitari-kontrola egiten zaio eta zainduta egoten da bere familiarengana itzuli arte edo familia berri bat aurkitu arte.

+

Guretzat animalia bakoitza norbait da, bere istorio, beldur eta izaerarekin. Ondo ezagutzen saiatzen gara, nolakoa den eta zer behar duen zintzotasunez kontatzeko.

-

Animalien Ongizaterako Legea betez, animalia guztiek beharrezko tratamenduak jasotzen dituzte adoptatu aurretik:

+

Adoptatu aurretik, guztiek mikrotxipa, txertoak, desparasitazioa eta antzutzea jasotzen dituzte.

- - - - - -
-

Adoptatu eta bi mundu aldatu: berea eta zurea.

-
- - -

Zure animalia galdu duzu?

+

Zer bilatzen dugun haientzat

-

Zure txakurra edo katua Irunen edo Hondarribian galdu baduzu, deitu iezaguzu lehenbailehen 943 64 52 79 zenbakira eta jakinarazi Udaltzaingoari ere. Mikrotxipa eguneratuta izatea da etxera itzultzeko modurik onena.

+

Ez dugu familia perfekturik bilatzen, animalia bakoitzarekin bat datozen eta haren erritmoa errespetatzen duten familiak baizik. Horregatik presarik gabe goaz: lehenik elkar ezagutu eta gero elkarrekin baloratzen dugu.

+ + +
+
Ezagutu animaliak
+ + + +
Lagundu
+
+ diff --git a/docker/content/eu/ohiko-galderak.html b/docker/content/eu/ohiko-galderak.html new file mode 100644 index 0000000..47b796a --- /dev/null +++ b/docker/content/eu/ohiko-galderak.html @@ -0,0 +1,39 @@ + +
Nola adopta dezaket? +

Sartu interesatzen zaizun animaliaren fitxan eta sakatu «Ezagutu nahi dut». Gure galdetegia bidaliko dizugu, taldearekin baloratuko dugu eta elkar ezagutzeko geratuko gara. Eskaera bidaltzeak ez du adopzioa baieztatzen.

+
+ + + +
Zuzenean joan naiteke animaliak ezagutzera? +

Bisitak beti aurretiko hitzorduarekin dira. Idatzi edo deitu iezaguzu eta une bat bilatuko dugu.

+
+ + + +
Zer dakar harrera batek? +

Animalia bati aldi baterako etxe bat eskaintzea, bere familia aurkitu bitartean. Iraupena, gastuak, materiala eta laguntza zurekin zehazten ditugu kasu bakoitzean.

+
+ + + +
Nola egin dezaket boluntariotza? +

Idatzi iezaguzu: lehen hitzordu bat hitzartu eta galdetegi bat betetzen dugu. Ibilaldietarako, konpainiarako eta sozializaziorako laguntza bilatzen dugu.

+
+ + + +
Zer material behar duzue? +

Zerrenda eguneratua Lagundu atalean duzu. Ezer ekarri aurretik, idatzi iezaguzu entrega zehazteko.

+
+ + + +
Adopta dezaket beste animaliak baditut? +

Kasuaren araberakoa da. Kontaiguzu idazten diguzunean eta elkarrekin baloratuko dugu taldearekin.

+
+ + + +

Ez duzu zure erantzuna aurkitzen? Idatzi iezaguzu.

+ diff --git a/docker/setup-content.php b/docker/setup-content.php index 25f6b1f..762b106 100644 --- a/docker/setup-content.php +++ b/docker/setup-content.php @@ -1,45 +1,49 @@ model; $existing = wp_list_pluck( $model->get_languages_list(), 'slug' ); - $langs = array( + foreach ( array( array( 'locale' => 'es_ES', 'slug' => 'es', 'name' => 'Español', 'flag' => 'es', 'term_group' => 0 ), array( 'locale' => 'eu', 'slug' => 'eu', 'name' => 'Euskara', 'flag' => 'basque', 'term_group' => 1 ), - ); - foreach ( $langs as $lang ) { - if ( in_array( $lang['slug'], $existing, true ) ) { - continue; - } - $result = $model->add_language( $lang ); - if ( is_wp_error( $result ) ) { - WP_CLI::warning( 'No se pudo crear el idioma ' . $lang['slug'] . ': ' . $result->get_error_message() ); + ) as $lang ) { + if ( ! in_array( $lang['slug'], $existing, true ) ) { + $result = $model->add_language( $lang ); + if ( is_wp_error( $result ) ) { + WP_CLI::warning( 'No se pudo crear el idioma ' . $lang['slug'] . ': ' . $result->get_error_message() ); + } } } $model->clean_languages_cache(); $settings = array( - 'default_lang' => 'es', - 'force_lang' => 1, // Idioma en el directorio: /eu/... - 'hide_default' => true, // Castellano sin prefijo. - 'rewrite' => true, // /eu/ en lugar de /language/eu/. - 'redirect_lang' => true, // Portada en euskera en /eu/ (no /eu/hasiera/). - 'browser' => false, - 'post_types' => array( 'animal' ), - 'taxonomies' => array( 'especie' ), - 'sync' => array( 'taxonomies', 'post_meta', '_thumbnail_id', 'menu_order', 'post_parent' ), + 'default_lang' => 'es', + 'force_lang' => 1, // Idioma en el directorio: /eu/... + 'hide_default' => true, // Castellano sin prefijo. + 'rewrite' => true, // /eu/ en lugar de /language/eu/. + 'redirect_lang' => true, // Portada en euskera en /eu/. + 'browser' => false, + 'post_types' => array( 'animal' ), + 'taxonomies' => array( 'especie' ), + 'sync' => array( 'taxonomies', 'post_meta', '_thumbnail_id', 'menu_order', 'post_parent' ), ); $options = PLL()->options; if ( is_object( $options ) && method_exists( $options, 'set' ) ) { @@ -52,7 +56,6 @@ if ( $pll ) { } else { update_option( 'polylang', array_merge( (array) get_option( 'polylang', array() ), $settings ) ); } - // Traducción al euskera del lema del sitio. if ( class_exists( 'PLL_MO' ) && ( $eu = $model->get_language( 'eu' ) ) ) { $mo = new PLL_MO(); $mo->import_from_db( $eu ); @@ -62,25 +65,46 @@ if ( $pll ) { if ( class_exists( 'PLL_Admin_Notices' ) ) { PLL_Admin_Notices::dismiss( 'wizard' ); } - WP_CLI::log( '[ga-setup] Idiomas: castellano (por defecto) y euskera' ); } /* ---------- 2. Páginas ---------- */ -function ga_setup_page( $slug, $title, $file, $lang ) { - $existing = get_page_by_path( $slug, OBJECT, 'page' ); - if ( $existing ) { - return $existing->ID; + +/** ¿La página sigue con el contenido que pusimos nosotros? */ +function ga_setup_untouched( WP_Post $post ) { + $hash = get_post_meta( $post->ID, '_ga_seed_hash', true ); + if ( $hash ) { + return md5( $post->post_content ) === $hash; } - $content = file_get_contents( $file ); - $id = wp_insert_post( array( - 'post_type' => 'page', - 'post_status' => 'publish', - 'post_title' => $title, - 'post_name' => $slug, - 'post_content' => $content, - ), true ); - if ( is_wp_error( $id ) ) { - WP_CLI::error( "No se pudo crear la página $slug: " . $id->get_error_message() ); + // Páginas de la primera instalación (sin huella): intactas si nunca se han modificado. + return $post->post_modified_gmt === $post->post_date_gmt; +} + +function ga_setup_page( $slug, $title, $file, $lang ) { + $content = file_exists( $file ) ? file_get_contents( $file ) : ''; + $page = get_page_by_path( $slug, OBJECT, 'page' ); + + if ( $page && 'trash' !== $page->post_status ) { + if ( $content && ga_setup_untouched( $page ) && trim( $page->post_content ) !== trim( $content ) ) { + wp_update_post( array( 'ID' => $page->ID, 'post_content' => $content, 'post_title' => $title ) ); + update_post_meta( $page->ID, '_ga_seed_hash', md5( get_post( $page->ID )->post_content ) ); + WP_CLI::log( "[ga-setup] actualizada: $slug" ); + } elseif ( ! ga_setup_untouched( $page ) ) { + WP_CLI::log( "[ga-setup] se respeta (editada): $slug" ); + } + $id = $page->ID; + } else { + $id = wp_insert_post( array( + 'post_type' => 'page', + 'post_status' => 'publish', + 'post_title' => $title, + 'post_name' => $slug, + 'post_content' => $content, + ), true ); + if ( is_wp_error( $id ) ) { + WP_CLI::error( "No se pudo crear la página $slug: " . $id->get_error_message() ); + } + update_post_meta( $id, '_ga_seed_hash', md5( get_post( $id )->post_content ) ); + WP_CLI::log( "[ga-setup] creada: $slug" ); } if ( function_exists( 'pll_set_post_language' ) ) { pll_set_post_language( $id, $lang ); @@ -88,43 +112,50 @@ function ga_setup_page( $slug, $title, $file, $lang ) { return $id; } -// slug es => [título es, archivo es, slug eu, título eu, archivo eu] +// slug es => [título es, slug eu, título eu] $pages = array( - 'inicio' => array( 'Inicio', 'inicio', 'hasiera', 'Hasiera', 'hasiera' ), - 'quienes-somos' => array( 'Quiénes somos', 'quienes-somos', 'nor-gara', 'Nor gara', 'nor-gara' ), - 'colabora' => array( 'Colabora', 'colabora', 'lagundu', 'Lagundu', 'lagundu' ), - 'hotel' => array( 'Hotel para perros y gatos', 'hotel', 'hotela', 'Txakur eta katuentzako hotela', 'hotela' ), - 'contacto' => array( 'Contacto', 'contacto', 'harremanetarako', 'Harremanetarako', 'harremanetarako' ), - 'politica-de-privacidad' => array( 'Política de privacidad', 'privacidad', 'pribatutasun-politika', 'Pribatutasun-politika', 'pribatutasun-politika' ), - 'aviso-legal' => array( 'Aviso legal', 'aviso-legal', 'lege-oharra', 'Lege-oharra', 'lege-oharra' ), + 'inicio' => array( 'Inicio', 'hasiera', 'Hasiera' ), + 'acoge' => array( 'Acoge', 'harrera', 'Harrera' ), + 'colabora' => array( 'Colabora', 'lagundu', 'Lagundu' ), + 'quienes-somos' => array( 'Quiénes somos', 'nor-gara', 'Nor gara' ), + 'contacto' => array( 'Contacto', 'harremanetarako', 'Harremanetarako' ), + 'preguntas-frecuentes' => array( 'Preguntas frecuentes', 'ohiko-galderak', 'Ohiko galderak' ), + 'politica-de-privacidad' => array( 'Política de privacidad', 'pribatutasun-politika', 'Pribatutasun-politika' ), + 'aviso-legal' => array( 'Aviso legal', 'lege-oharra', 'Lege-oharra' ), ); +$files = array( 'politica-de-privacidad' => 'privacidad' ); $ids = array(); -foreach ( $pages as $slug => [ $title_es, $file_es, $slug_eu, $title_eu, $file_eu ] ) { - $ids[ $slug ]['es'] = ga_setup_page( $slug, $title_es, "$src/es/$file_es.html", 'es' ); +foreach ( $pages as $slug => [ $title_es, $slug_eu, $title_eu ] ) { + $ids[ $slug ]['es'] = ga_setup_page( $slug, $title_es, "$src/es/" . ( $files[ $slug ] ?? $slug ) . '.html', 'es' ); if ( $pll ) { - $ids[ $slug ]['eu'] = ga_setup_page( $slug_eu, $title_eu, "$src/eu/$file_eu.html", 'eu' ); + $ids[ $slug ]['eu'] = ga_setup_page( $slug_eu, $title_eu, "$src/eu/$slug_eu.html", 'eu' ); pll_save_post_translations( $ids[ $slug ] ); } } +// El hotel ya no forma parte de la web: se retira si nadie lo ha editado. +foreach ( array( 'hotel', 'hotela' ) as $slug ) { + $page = get_page_by_path( $slug, OBJECT, 'page' ); + if ( $page && 'trash' !== $page->post_status ) { + if ( ga_setup_untouched( $page ) ) { + wp_trash_post( $page->ID ); + WP_CLI::log( "[ga-setup] a la papelera: $slug" ); + } else { + WP_CLI::warning( "La página «$slug» se ha editado: no se borra, revísala a mano." ); + } + } +} + update_option( 'show_on_front', 'page' ); update_option( 'page_on_front', $ids['inicio']['es'] ); update_option( 'wp_page_for_privacy_policy', $ids['politica-de-privacidad']['es'] ); -WP_CLI::log( '[ga-setup] Páginas creadas' ); +WP_CLI::log( '[ga-setup] Páginas listas' ); -/* ---------- 3. Especies ---------- */ -$species = array( - 'perro' => array( 'Perro', 'txakurra', 'Txakurra' ), - 'gato' => array( 'Gato', 'katua', 'Katua' ), - 'otros' => array( 'Otros', 'besteak', 'Besteak' ), -); +/* ---------- 3. Especies: solo perros y gatos ---------- */ $term_ids = array(); -foreach ( $species as $slug => [ $name_es, $slug_eu, $name_eu ] ) { - $pairs = array( 'es' => array( $slug, $name_es ) ); - if ( $pll ) { - $pairs['eu'] = array( $slug_eu, $name_eu ); - } +foreach ( array( 'perro' => array( 'Perro', 'txakurra', 'Txakurra' ), 'gato' => array( 'Gato', 'katua', 'Katua' ) ) as $slug => [ $name_es, $slug_eu, $name_eu ] ) { + $pairs = array( 'es' => array( $slug, $name_es ) ) + ( $pll ? array( 'eu' => array( $slug_eu, $name_eu ) ) : array() ); foreach ( $pairs as $lang => [ $term_slug, $term_name ] ) { $term = get_term_by( 'slug', $term_slug, 'especie' ); if ( ! $term ) { @@ -138,64 +169,95 @@ foreach ( $species as $slug => [ $name_es, $slug_eu, $name_eu ] ) { } } } - if ( $pll && count( $term_ids[ $slug ] ?? array() ) === 2 ) { + if ( $pll && 2 === count( $term_ids[ $slug ] ?? array() ) ) { pll_save_term_translations( $term_ids[ $slug ] ); } } +foreach ( array( 'otros', 'besteak' ) as $slug ) { + $term = get_term_by( 'slug', $slug, 'especie' ); + if ( $term && 0 === (int) $term->count ) { + wp_delete_term( $term->term_id, 'especie' ); + } +} /* ---------- 4. Menús ---------- */ -function ga_setup_menu( $name, $items ) { +function ga_setup_menu( $name, $items, $rebuild ) { $menu = wp_get_nav_menu_object( $name ); - if ( $menu ) { + if ( $menu && ! $rebuild ) { return $menu->term_id; } + if ( $menu ) { + wp_delete_nav_menu( $menu->term_id ); + } $menu_id = wp_create_nav_menu( $name ); - foreach ( $items as $pos => $item ) { - $args = array( 'menu-item-status' => 'publish', 'menu-item-position' => $pos + 1, 'menu-item-title' => $item['title'] ); - if ( isset( $item['page'] ) ) { - $args += array( 'menu-item-type' => 'post_type', 'menu-item-object' => 'page', 'menu-item-object-id' => $item['page'] ); - } else { - $args += array( 'menu-item-type' => 'custom', 'menu-item-url' => $item['url'] ); + $pos = 0; + $add = function ( $item, $parent = 0 ) use ( $menu_id, &$pos, &$add ) { + $args = array( + 'menu-item-status' => 'publish', + 'menu-item-position' => ++$pos, + 'menu-item-title' => $item['title'], + 'menu-item-parent-id' => $parent, + ); + $args += isset( $item['page'] ) + ? array( 'menu-item-type' => 'post_type', 'menu-item-object' => 'page', 'menu-item-object-id' => $item['page'] ) + : array( 'menu-item-type' => 'custom', 'menu-item-url' => $item['url'] ); + $id = wp_update_nav_menu_item( $menu_id, 0, $args ); + foreach ( $item['children'] ?? array() as $child ) { + $add( $child, $id ); } - wp_update_nav_menu_item( $menu_id, 0, $args ); + }; + foreach ( $items as $item ) { + $add( $item ); } return $menu_id; } -$menus = array( +$rebuild = 'true' === getenv( 'GA_SEED_MENUS' ); +$menus = array( 'primary' => array( 'es' => ga_setup_menu( 'Principal', array( - array( 'title' => 'Adopta', 'url' => '/adopta/' ), - array( 'title' => 'Acoge', 'url' => '/colabora/#acogida' ), - array( 'title' => 'Voluntariado', 'url' => '/colabora/#voluntariado' ), - array( 'title' => 'Dona', 'url' => '/colabora/#donaciones' ), - array( 'title' => 'Hotel', 'page' => $ids['hotel']['es'] ), + array( 'title' => 'Inicio', 'page' => $ids['inicio']['es'] ), + array( 'title' => 'Adopta', 'url' => '/adopta/', 'children' => array( + array( 'title' => 'Perros', 'url' => '/especie/perro/' ), + array( 'title' => 'Gatos', 'url' => '/especie/gato/' ), + ) ), + array( 'title' => 'Acoge', 'page' => $ids['acoge']['es'] ), + array( 'title' => 'Colabora', 'page' => $ids['colabora']['es'], 'children' => array( + array( 'title' => 'Voluntariado', 'url' => '/colabora/#voluntariado' ), + array( 'title' => 'Ayuda material', 'url' => '/colabora/#material' ), + ) ), + array( 'title' => 'Quiénes somos', 'page' => $ids['quienes-somos']['es'] ), array( 'title' => 'Contacto', 'page' => $ids['contacto']['es'] ), - ) ), + ), $rebuild ), ), 'footer' => array( 'es' => ga_setup_menu( 'Legal', array( array( 'title' => 'Aviso legal', 'page' => $ids['aviso-legal']['es'] ), array( 'title' => 'Política de privacidad', 'page' => $ids['politica-de-privacidad']['es'] ), - ) ), + ), $rebuild ), ), ); if ( $pll ) { $menus['primary']['eu'] = ga_setup_menu( 'Nagusia (euskara)', array( - array( 'title' => 'Adoptatu', 'url' => '/eu/adopta/' ), - array( 'title' => 'Harrera', 'url' => '/eu/lagundu/#acogida' ), - array( 'title' => 'Boluntariotza', 'url' => '/eu/lagundu/#voluntariado' ), - array( 'title' => 'Dohaintza', 'url' => '/eu/lagundu/#donaciones' ), - array( 'title' => 'Hotela', 'page' => $ids['hotel']['eu'] ), + array( 'title' => 'Hasiera', 'page' => $ids['inicio']['eu'] ), + array( 'title' => 'Adoptatu', 'url' => '/eu/adopta/', 'children' => array( + array( 'title' => 'Txakurrak', 'url' => '/eu/especie/txakurra/' ), + array( 'title' => 'Katuak', 'url' => '/eu/especie/katua/' ), + ) ), + array( 'title' => 'Harrera', 'page' => $ids['acoge']['eu'] ), + array( 'title' => 'Lagundu', 'page' => $ids['colabora']['eu'], 'children' => array( + array( 'title' => 'Boluntariotza', 'url' => '/eu/lagundu/#voluntariado' ), + array( 'title' => 'Laguntza materiala', 'url' => '/eu/lagundu/#material' ), + ) ), + array( 'title' => 'Nor gara', 'page' => $ids['quienes-somos']['eu'] ), array( 'title' => 'Harremanetarako', 'page' => $ids['contacto']['eu'] ), - ) ); + ), $rebuild ); $menus['footer']['eu'] = ga_setup_menu( 'Legala (euskara)', array( array( 'title' => 'Lege-oharra', 'page' => $ids['aviso-legal']['eu'] ), array( 'title' => 'Pribatutasun-politika', 'page' => $ids['politica-de-privacidad']['eu'] ), - ) ); + ), $rebuild ); - $theme = get_stylesheet(); - $nav_menus = array( $theme => $menus ); + $nav_menus = array( get_stylesheet() => $menus ); if ( is_object( PLL()->options ) && method_exists( PLL()->options, 'set' ) ) { PLL()->options->set( 'nav_menus', $nav_menus ); if ( method_exists( PLL()->options, 'save_all' ) ) { @@ -207,44 +269,51 @@ if ( $pll ) { update_option( 'polylang', $opts ); } } -set_theme_mod( 'nav_menu_locations', array( - 'primary' => $menus['primary']['es'], - 'footer' => $menus['footer']['es'], -) ); -WP_CLI::log( '[ga-setup] Menús creados' ); +set_theme_mod( 'nav_menu_locations', array( 'primary' => $menus['primary']['es'], 'footer' => $menus['footer']['es'] ) ); +WP_CLI::log( '[ga-setup] Menús listos' ); -/* ---------- 5. Animales de ejemplo (opcional) ---------- */ -if ( 'true' === getenv( 'SEED_DEMO_ANIMALS' ) ) { +/* ---------- 5. Animales ---------- */ + +// Estados antiguos → nuevos (disponible / proceso / adoptado). +foreach ( get_posts( array( 'post_type' => 'animal', 'post_status' => 'any', 'numberposts' => -1, 'fields' => 'ids', 'lang' => '' ) ) as $animal_id ) { + $estado = get_post_meta( $animal_id, '_ga_estado', true ); + $map = array( 'reservado' => 'proceso', 'urgente' => 'disponible', 'acogida' => 'disponible' ); + if ( isset( $map[ $estado ] ) ) { + update_post_meta( $animal_id, '_ga_estado', $map[ $estado ] ); + } +} + +if ( 'true' === getenv( 'SEED_DEMO_ANIMALS' ) && ! get_posts( array( 'post_type' => 'animal', 'numberposts' => 1, 'post_status' => 'any', 'lang' => '' ) ) ) { $demo = array( array( - 'es' => array( 'Txuri (ejemplo)', 'Txuri es cariñosa, tranquila en casa y le encantan los paseos por Jaizkibel.' ), - 'eu' => array( 'Txuri (adibidea)', 'Txuri maitekorra da, lasaia etxean, eta Jaizkibelen barrena paseatzea asko gustatzen zaio.' ), + 'es' => array( 'Txuri (ejemplo)', 'Llegó un poco asustada, pero en cuanto coge confianza no se separa de ti.', array( 'caracter' => 'Tranquila en casa y muy cariñosa con quien conoce. Le encantan los paseos largos.', 'hogar' => 'Una familia que respete su ritmo y le acompañe con paciencia.' ) ), + 'eu' => array( 'Txuri (adibidea)', 'Beldur pixka batekin iritsi zen, baina konfiantza hartzen duenean ez da zure ondotik aldentzen.', array( 'caracter' => 'Lasaia etxean eta oso maitekorra ezagutzen dituenekin. Ibilaldi luzeak asko gustatzen zaizkio.', 'hogar' => 'Bere erritmoa errespetatu eta pazientziaz lagunduko dion familia bat.' ) ), 'sp' => 'perro', - 'meta' => array( 'sexo' => 'hembra', 'edad' => '3', 'edad_unidad' => 'anos', 'tamano' => 'mediano', 'estado' => 'disponible', 'raza' => 'Mestiza' ), + 'meta' => array( 'sexo' => 'hembra', 'edad' => '3', 'edad_unidad' => 'anos', 'tamano' => 'mediano', 'estado' => 'disponible', 'destacado' => '1' ), ), array( - 'es' => array( 'Beltza (ejemplo)', 'Beltza es un gato curioso y juguetón que busca un hogar sin prisas.' ), - 'eu' => array( 'Beltza (adibidea)', 'Beltza katu jakin-nahia eta jostalaria da, eta presarik gabe etxe baten bila dabil.' ), + 'es' => array( 'Beltza (ejemplo)', 'Curioso y juguetón, siempre quiere saber qué estás haciendo.', array( 'caracter' => 'Muy sociable con las personas. Le gusta jugar y dormir al sol.' ) ), + 'eu' => array( 'Beltza (adibidea)', 'Jakin-mina eta jostalaria, beti jakin nahi du zer egiten ari zaren.', array( 'caracter' => 'Oso soziala pertsonekin. Jolastea eta eguzkitan lo egitea gustatzen zaizkio.' ) ), 'sp' => 'gato', - 'meta' => array( 'sexo' => 'macho', 'edad' => '1', 'edad_unidad' => 'anos', 'tamano' => 'pequeno', 'estado' => 'disponible', 'raza' => 'Común europeo' ), + 'meta' => array( 'sexo' => 'macho', 'edad' => '1', 'edad_unidad' => 'anos', 'estado' => 'disponible' ), ), array( - 'es' => array( 'Hartz (ejemplo)', 'Hartz es un abuelito noble que merece pasar sus mejores años en familia.' ), - 'eu' => array( 'Hartz (adibidea)', 'Hartz aitona noblea da, eta bere urterik onenak familian igarotzea merezi du.' ), + 'es' => array( 'Hartz (ejemplo)', 'Un abuelito noble que merece pasar sus mejores años en familia.', array( 'necesidades' => 'Paseos tranquilos y una casa sin muchas escaleras.' ) ), + 'eu' => array( 'Hartz (adibidea)', 'Aitona noblea, bere urterik onenak familian igarotzea merezi duena.', array( 'necesidades' => 'Ibilaldi lasaiak eta eskailera askorik gabeko etxea.' ) ), 'sp' => 'perro', - 'meta' => array( 'sexo' => 'macho', 'edad' => '7', 'edad_unidad' => 'anos', 'tamano' => 'grande', 'estado' => 'urgente', 'raza' => 'Mastín' ), + 'meta' => array( 'sexo' => 'macho', 'edad' => '9', 'edad_unidad' => 'anos', 'tamano' => 'grande', 'estado' => 'disponible', 'destacado' => '1' ), ), array( - 'es' => array( 'Ilargi (ejemplo)', 'Ilargi es una gatita sociable que se lleva bien con otros gatos.' ), - 'eu' => array( 'Ilargi (adibidea)', 'Ilargi katakume soziala da eta beste katuekin ondo moldatzen da.' ), + 'es' => array( 'Ilargi (ejemplo)', 'Una gatita sociable que se lleva bien con otros gatos.', array() ), + 'eu' => array( 'Ilargi (adibidea)', 'Beste katuekin ondo moldatzen den katakume soziala.', array() ), 'sp' => 'gato', - 'meta' => array( 'sexo' => 'hembra', 'edad' => '4', 'edad_unidad' => 'meses', 'tamano' => 'pequeno', 'estado' => 'reservado', 'raza' => 'Común europeo' ), + 'meta' => array( 'sexo' => 'hembra', 'edad' => '4', 'edad_unidad' => 'meses', 'estado' => 'proceso' ), ), ); foreach ( $demo as $animal ) { $translations = array(); foreach ( $pll ? array( 'es', 'eu' ) : array( 'es' ) as $lang ) { - [ $title, $text ] = $animal[ $lang ]; + [ $title, $text, $texts ] = $animal[ $lang ]; $id = wp_insert_post( array( 'post_type' => 'animal', 'post_status' => 'publish', @@ -254,7 +323,7 @@ if ( 'true' === getenv( 'SEED_DEMO_ANIMALS' ) ) { if ( ! empty( $term_ids[ $animal['sp'] ][ $lang ] ) ) { wp_set_object_terms( $id, array( $term_ids[ $animal['sp'] ][ $lang ] ), 'especie' ); } - foreach ( $animal['meta'] + array( 'salud' => 'chip,vacunado,esterilizado', 'compatible' => 'perros,ninos' ) as $key => $value ) { + foreach ( $animal['meta'] + $texts as $key => $value ) { update_post_meta( $id, "_ga_$key", $value ); } if ( $pll ) { diff --git a/docker/setup.sh b/docker/setup.sh index d29e258..451c902 100644 --- a/docker/setup.sh +++ b/docker/setup.sh @@ -103,7 +103,7 @@ if (( VERSION < 2 )); then wp_ language plugin install polylang es_ES eu 2>/dev/null || true # Idiomas, páginas, especies, menús y (opcional) animales de ejemplo - if ! wp_ eval-file "$SRC/setup-content.php"; then + if ! GA_SEED_MENUS=true wp_ eval-file "$SRC/setup-content.php"; then log "Fallo creando el contenido inicial" exit 1 fi @@ -127,7 +127,6 @@ if (( VERSION < 3 )); then instagram-feed # Feed de Instagram koko-analytics # Estadísticas sin cookies kadence-blocks # Bloques visuales: carruseles, pestañas, acordeones… - blocks-animation # Animaciones de entrada para cualquier bloque ) # Instalados pero desactivados: se activan cuando se necesiten INACTIVE=( @@ -170,4 +169,18 @@ if (( VERSION < 4 )); then wp_ option update ga_setup_version 4 fi +# Etapa 5: indicaciones del cliente (adopción solo Perros/Gatos, fichas nuevas, sin hotel ni donaciones) +if (( VERSION < 5 )); then + log "Migración 5: páginas, menús y fichas nuevas" + # Crea las páginas nuevas, actualiza solo las que nadie ha editado, retira el hotel y rehace los menús + if ! GA_SEED_MENUS=true wp_ eval-file "$SRC/setup-content.php"; then + log "Fallo en la migración 5" + exit 1 + fi + # Sin animaciones que distraigan + wp_ plugin deactivate blocks-animation >/dev/null 2>&1 || true + wp_ rewrite flush + wp_ option update ga_setup_version 5 +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 95cfcc5..256fc2b 100644 --- a/wp-content/mu-plugins/gure-ametsa-core.php +++ b/wp-content/mu-plugins/gure-ametsa-core.php @@ -1,764 +1,14 @@ ID; - if ( function_exists( 'pll_get_post' ) ) { - $id = pll_get_post( $id, ga_lang() ) ?: $id; - } - return get_permalink( $id ) . $fragment; -} - -/* Animales y especies son traducibles; los mensajes no. */ -add_filter( 'pll_get_post_types', function ( $types, $is_settings ) { - $types['animal'] = 'animal'; - unset( $types['ga_mensaje'] ); - return $types; -}, 10, 2 ); - -add_filter( 'pll_get_taxonomies', function ( $taxonomies ) { - $taxonomies['especie'] = 'especie'; - return $taxonomies; -} ); - -/* ------------------------------------------------------------------------- - * Datos de la protectora - * ---------------------------------------------------------------------- */ - -function ga_info( $key = null ) { - $info = apply_filters( 'ga_info', array( - 'nombre' => 'Gure Ametsa Bi Lagun', - 'direccion' => 'Jaizubia, 44 · 20280 Hondarribia (Gipuzkoa)', - 'telefono' => '943 64 52 79', - 'email' => 'hola@gureametsabilagun.org', - 'horario' => ga__( 'Lunes a viernes: 10:00–13:00 y 14:00–19:00', 'Astelehenetik ostiralera: 10:00–13:00 eta 14:00–19:00' ), - 'instagram' => 'https://www.instagram.com/gureametsabilagun/', - 'facebook' => 'https://www.facebook.com/gureametsabilagun/', - 'maps' => 'https://www.google.com/maps/search/?api=1&query=Jaizubia+44+Hondarribia', - ) ); - return $key ? ( $info[ $key ] ?? '' ) : $info; -} - -function ga_contact_email() { - $email = getenv( 'GA_CONTACT_EMAIL' ); - return is_email( $email ) ? $email : get_option( 'admin_email' ); -} - -/* ------------------------------------------------------------------------- - * Tipos de contenido y taxonomías - * ---------------------------------------------------------------------- */ - -add_action( 'init', function () { - register_post_type( 'animal', array( - 'labels' => array( - 'name' => 'Animales', - 'singular_name' => 'Animal', - 'add_new' => 'Añadir animal', - 'add_new_item' => 'Añadir nuevo animal', - 'edit_item' => 'Editar animal', - 'new_item' => 'Nuevo animal', - 'view_item' => 'Ver ficha', - 'search_items' => 'Buscar animales', - 'not_found' => 'No hay animales', - 'not_found_in_trash' => 'No hay animales en la papelera', - 'all_items' => 'Todos los animales', - 'featured_image' => 'Foto principal', - 'set_featured_image' => 'Elegir foto principal', - 'menu_name' => 'Animales', - ), - 'public' => true, - 'has_archive' => 'adopta', - 'rewrite' => array( 'slug' => 'adopta', 'with_front' => false ), - 'menu_icon' => 'dashicons-pets', - '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( - 'labels' => array( - 'name' => 'Especies', - 'singular_name' => 'Especie', - 'add_new_item' => 'Añadir especie', - ), - '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 ), - ) ); - - register_post_type( 'ga_mensaje', array( - 'labels' => array( - 'name' => 'Mensajes', - 'singular_name' => 'Mensaje', - 'edit_item' => 'Mensaje', - 'all_items' => 'Mensajes recibidos', - 'not_found' => 'Aún no hay mensajes', - ), - 'public' => false, - 'show_ui' => true, - 'menu_icon' => 'dashicons-email-alt', - 'menu_position' => 6, - 'supports' => array( 'title', 'editor' ), - 'capability_type' => 'post', - 'capabilities' => array( 'create_posts' => 'do_not_allow' ), - 'map_meta_cap' => true, - ) ); - - foreach ( array_keys( ga_fields() ) as $key ) { - register_post_meta( 'animal', "_ga_$key", array( - 'type' => 'string', - 'single' => true, - 'show_in_rest' => true, - 'auth_callback' => function () { return current_user_can( 'edit_posts' ); }, - ) ); - } -} ); - -/* ------------------------------------------------------------------------- - * Campos de la ficha (etiquetas en el idioma actual) - * ---------------------------------------------------------------------- */ - -function ga_fields() { - return array( - 'estado' => array( 'label' => ga__( 'Estado', 'Egoera' ), 'type' => 'select', 'options' => array( - 'disponible' => ga__( 'En adopción', 'Adopzioan' ), - 'urgente' => ga__( 'Adopción urgente', 'Adopzio premiazkoa' ), - 'acogida' => ga__( 'Busca casa de acogida', 'Harrera-etxe bila' ), - 'reservado' => ga__( 'Reservado', 'Erreserbatuta' ), - 'adoptado' => ga__( 'Adoptado', 'Adoptatuta' ), - ) ), - 'sexo' => array( 'label' => ga__( 'Sexo', 'Sexua' ), 'type' => 'select', 'options' => array( - 'macho' => ga__( 'Macho', 'Arra' ), - 'hembra' => ga__( 'Hembra', 'Emea' ), - ) ), - 'edad' => array( 'label' => ga__( 'Edad', 'Adina' ), 'type' => 'number', 'placeholder' => 'p. ej. 2' ), - 'edad_unidad' => array( 'label' => ga__( 'Edad en', 'Adina' ), 'type' => 'select', 'options' => array( - 'anos' => ga__( 'Años', 'Urteak' ), - 'meses' => ga__( 'Meses', 'Hilabeteak' ), - ) ), - 'tamano' => array( 'label' => ga__( 'Tamaño', 'Tamaina' ), 'type' => 'select', 'options' => array( - 'pequeno' => ga__( 'Pequeño', 'Txikia' ), - 'mediano' => ga__( 'Mediano', 'Ertaina' ), - 'grande' => ga__( 'Grande', 'Handia' ), - ) ), - 'raza' => array( 'label' => ga__( 'Raza', 'Arraza' ), 'type' => 'text', 'placeholder' => 'p. ej. Mestizo' ), - 'llegada' => array( 'label' => ga__( 'Fecha de llegada', 'Iritsiera-data' ), 'type' => 'date' ), - 'salud' => array( 'label' => ga__( 'Salud', 'Osasuna' ), 'type' => 'checks', 'options' => array( - 'chip' => ga__( 'Microchip', 'Mikrotxipa' ), - 'vacunado' => ga__( 'Vacunado', 'Txertatuta' ), - 'esterilizado' => ga__( 'Esterilizado', 'Antzututa' ), - 'desparasitado' => ga__( 'Desparasitado', 'Desparasitatuta' ), - ) ), - 'compatible' => array( 'label' => ga__( 'Se lleva bien con', 'Ondo moldatzen da hauekin' ), 'type' => 'checks', 'options' => array( - 'ninos' => ga__( 'Niños', 'Haurrak' ), - 'perros' => ga__( 'Perros', 'Txakurrak' ), - 'gatos' => ga__( 'Gatos', 'Katuak' ), - ) ), - ); -} - -/** Edad legible en el idioma actual: «3 años», «1 mes», «3 urte», «4 hilabete». */ -function ga_age( $post_id ) { - $n = ga_get( $post_id, 'edad' ); - if ( '' === $n || ! is_numeric( $n ) ) { - return $n; // Valores antiguos en texto libre. - } - $n = (float) $n + 0; - $months = 'meses' === ga_get( $post_id, 'edad_unidad' ); - if ( 'eu' === ga_lang() ) { - return $n . ( $months ? ' hilabete' : ' urte' ); - } - if ( $months ) { - return $n . ( 1 == $n ? ' mes' : ' meses' ); - } - return $n . ( 1 == $n ? ' año' : ' años' ); -} - -function ga_get( $post_id, $key ) { - return (string) get_post_meta( $post_id, "_ga_$key", true ); -} - -/** Etiqueta legible de un campo select, o lista de etiquetas de un campo checks. */ -function ga_label( $post_id, $key ) { - $fields = ga_fields(); - $value = ga_get( $post_id, $key ); - if ( '' === $value || ! isset( $fields[ $key ] ) ) { - return ''; - } - $field = $fields[ $key ]; - if ( 'select' === $field['type'] ) { - return $field['options'][ $value ] ?? $value; - } - if ( 'checks' === $field['type'] ) { - $labels = array(); - foreach ( explode( ',', $value ) as $v ) { - if ( isset( $field['options'][ $v ] ) ) { - $labels[] = $field['options'][ $v ]; - } - } - return $labels; - } - if ( 'date' === $field['type'] ) { - return date_i18n( get_option( 'date_format' ), strtotime( $value ) ); - } - return $value; -} - -add_action( 'add_meta_boxes_animal', function () { - add_meta_box( 'ga_ficha', 'Ficha del animal', 'ga_render_metabox', 'animal', 'normal', 'high' ); -} ); - -function ga_render_metabox( $post ) { - wp_nonce_field( 'ga_ficha', 'ga_ficha_nonce' ); - echo ''; - foreach ( ga_fields() as $key => $f ) { - $name = "ga_$key"; - $value = ga_get( $post->ID, $key ); - if ( 'estado' === $key && '' === $value ) { - $value = 'disponible'; - } - echo ''; - } - echo ''; - echo '

La ficha se comparte entre la versión en castellano y en euskera: al guardar una, se copia a la otra. Solo el nombre y la descripción se traducen.

'; - echo '

Consejo: la foto principal aparece en los listados. Añade más fotos en el contenido con el bloque «Galería».

'; -} - -add_action( 'save_post_animal', function ( $post_id ) { - if ( ! isset( $_POST['ga_ficha_nonce'] ) || ! wp_verify_nonce( $_POST['ga_ficha_nonce'], 'ga_ficha' ) ) { - return; - } - if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE || ! current_user_can( 'edit_post', $post_id ) ) { - return; - } - foreach ( ga_fields() as $key => $f ) { - $raw = $_POST[ "ga_$key" ] ?? ''; - if ( 'checks' === $f['type'] ) { - $raw = array_intersect( (array) $raw, array_keys( $f['options'] ) ); - $value = implode( ',', $raw ); - } elseif ( 'select' === $f['type'] ) { - $value = isset( $f['options'][ $raw ] ) ? $raw : ''; - } else { - $value = sanitize_text_field( wp_unslash( $raw ) ); - } - ga_update_meta_all_languages( $post_id, "_ga_$key", $value ); - } -} ); - -/** Guarda un campo en el animal y en todas sus traducciones. */ -function ga_update_meta_all_languages( $post_id, $meta_key, $value ) { - $ids = array( $post_id ); - if ( function_exists( 'pll_get_post_translations' ) ) { - $ids = array_unique( array_merge( $ids, array_values( pll_get_post_translations( $post_id ) ) ) ); - } - foreach ( $ids as $id ) { - update_post_meta( $id, $meta_key, $value ); - } -} - -/* Columnas en el listado del admin */ -add_filter( 'manage_animal_posts_columns', function ( $cols ) { - $new = array(); - foreach ( $cols as $k => $v ) { - if ( 'title' === $k ) { - $new['ga_foto'] = 'Foto'; - } - $new[ $k ] = $v; - if ( 'title' === $k ) { - $new['ga_estado'] = 'Estado'; - $new['ga_edad'] = 'Edad'; - } - } - return $new; -} ); - -add_action( 'manage_animal_posts_custom_column', function ( $col, $post_id ) { - if ( 'ga_foto' === $col ) { - echo get_the_post_thumbnail( $post_id, array( 60, 60 ) ); - } elseif ( 'ga_estado' === $col ) { - echo esc_html( ga_label( $post_id, 'estado' ) ); - } elseif ( 'ga_edad' === $col ) { - echo esc_html( ga_age( $post_id ) ); - } -}, 10, 2 ); - -/* Título de la pestaña del listado en el idioma actual */ -add_filter( 'document_title_parts', function ( $parts ) { - if ( is_post_type_archive( 'animal' ) ) { - $parts['title'] = ga__( 'Animales en adopción', 'Animaliak adopzioan' ); - } - return $parts; -} ); - -/* ------------------------------------------------------------------------- - * Consultas del listado público /adopta/ - * ---------------------------------------------------------------------- */ - -add_filter( 'query_vars', function ( $vars ) { - return array_merge( $vars, array( 'tamano', 'sexo', 'edad', 'con' ) ); -} ); - -/** Grupos de edad para el filtro del listado. */ -function ga_age_groups() { - return array( - 'joven' => ga__( 'Menos de 1 año', 'Urtebete baino gutxiago' ), - 'adulto' => ga__( 'Adulto', 'Heldua' ), - 'senior' => ga__( 'Mayor (8+)', 'Adinekoa (8+)' ), - ); -} - -/** meta_query para un grupo de edad (la edad se guarda como número + unidad). */ -function ga_age_meta_query( $group ) { - $anos = array( 'key' => '_ga_edad_unidad', 'value' => 'anos' ); - switch ( $group ) { - case 'joven': - return array( - 'relation' => 'OR', - array( 'key' => '_ga_edad_unidad', 'value' => 'meses' ), - array( 'relation' => 'AND', $anos, array( 'key' => '_ga_edad', 'value' => 1, 'compare' => '<', 'type' => 'NUMERIC' ) ), - ); - case 'adulto': - return array( 'relation' => 'AND', $anos, array( 'key' => '_ga_edad', 'value' => array( 1, 7 ), 'compare' => 'BETWEEN', 'type' => 'NUMERIC' ) ); - case 'senior': - return array( 'relation' => 'AND', $anos, array( 'key' => '_ga_edad', 'value' => 8, 'compare' => '>=', 'type' => 'NUMERIC' ) ); - } - return array(); -} - -function ga_not_adopted_meta_query() { - return array( - 'relation' => 'OR', - array( 'key' => '_ga_estado', 'value' => 'adoptado', 'compare' => '!=' ), - array( 'key' => '_ga_estado', 'compare' => 'NOT EXISTS' ), - ); -} - -add_action( 'pre_get_posts', function ( $q ) { - if ( is_admin() || ! $q->is_main_query() || ! ( $q->is_post_type_archive( 'animal' ) || $q->is_tax( 'especie' ) ) ) { - return; - } - $meta = array( ga_not_adopted_meta_query() ); - foreach ( array( 'tamano', 'sexo' ) as $key ) { - $v = sanitize_key( (string) $q->get( $key ) ); - if ( $v && isset( ga_fields()[ $key ]['options'][ $v ] ) ) { - $meta[] = array( 'key' => "_ga_$key", 'value' => $v ); - } - } - $edad = sanitize_key( (string) $q->get( 'edad' ) ); - if ( isset( ga_age_groups()[ $edad ] ) ) { - $meta[] = ga_age_meta_query( $edad ); - } - $con = sanitize_key( (string) $q->get( 'con' ) ); - if ( isset( ga_fields()['compatible']['options'][ $con ] ) ) { - $meta[] = array( 'key' => '_ga_compatible', 'value' => $con, 'compare' => 'LIKE' ); - } - $q->set( 'meta_query', $meta ); - $q->set( 'posts_per_page', 12 ); -} ); - -/** - * Consulta reutilizable de animales (Polylang filtra por el idioma actual). - */ -function ga_query_animals( $args = array() ) { - $args = wp_parse_args( $args, array( - 'numero' => 6, - 'especie' => '', - 'estado' => '', - ) ); - - $query = array( - 'post_type' => 'animal', - 'posts_per_page' => (int) $args['numero'], - 'no_found_rows' => true, - ); - if ( $args['especie'] ) { - $query['tax_query'] = array( array( - 'taxonomy' => 'especie', - 'field' => 'slug', - 'terms' => array_map( 'trim', explode( ',', $args['especie'] ) ), - ) ); - } - if ( $args['estado'] ) { - $query['meta_query'] = array( array( - 'key' => '_ga_estado', - 'value' => array_map( 'trim', explode( ',', $args['estado'] ) ), - 'compare' => 'IN', - ) ); - } else { - $query['meta_query'] = ga_not_adopted_meta_query(); - } - return new WP_Query( $query ); -} - -/* [ga_animales numero="6" especie="perro" estado="urgente" vista="carrusel"] */ -add_shortcode( 'ga_animales', function ( $atts ) { - $atts = shortcode_atts( array( 'numero' => 6, 'especie' => '', 'estado' => '', 'vista' => 'rejilla' ), $atts, 'ga_animales' ); - $q = ga_query_animals( $atts ); - ob_start(); - if ( $q->have_posts() ) { - $carousel = 'carrusel' === $atts['vista']; - if ( $carousel ) { - ga_carousel_open(); - } else { - echo '
'; - } - while ( $q->have_posts() ) { - $q->the_post(); - ga_animal_card(); - } - $carousel ? ga_carousel_close() : print( '
' ); - } else { - echo '

' . esc_html( ga__( 'Ahora mismo no hay animales en esta sección. ¡Vuelve pronto!', 'Une honetan ez dago animaliarik atal honetan. Itzuli laster!' ) ) . '

'; - } - wp_reset_postdata(); - return ob_get_clean(); -} ); - -/** Apertura y cierre de un carrusel accesible (el tema aporta el CSS y el JS). */ -function ga_carousel_open( $label = '' ) { - printf( - '', - esc_attr( ga__( 'Anteriores', 'Aurrekoak' ) ), - esc_attr( ga__( 'Siguientes', 'Hurrengoak' ) ) - ); -} - -/** Tarjeta de un animal (dentro del loop). El tema puede sobrescribirla con template-parts/animal-card.php. */ -function ga_animal_card() { - if ( locate_template( 'template-parts/animal-card.php' ) ) { - get_template_part( 'template-parts/animal-card' ); - return; - } - printf( '
%s
', esc_url( get_permalink() ), esc_html( get_the_title() ) ); -} - -/* ------------------------------------------------------------------------- - * Formulario de contacto / solicitud de adopción [ga_contacto] - * ---------------------------------------------------------------------- */ - -function ga_contact_reasons() { - return array( - 'adopcion' => ga__( 'Adopción', 'Adopzioa' ), - 'acogida' => ga__( 'Casa de acogida', 'Harrera-etxea' ), - 'voluntario' => ga__( 'Voluntariado', 'Boluntariotza' ), - 'donaciones' => ga__( 'Donaciones', 'Dohaintzak' ), - 'hotel' => ga__( 'Hotel para perros y gatos', 'Txakur eta katuentzako hotela' ), - 'perdido' => ga__( 'He encontrado / perdido un animal', 'Animalia bat aurkitu / galdu dut' ), - 'otro' => ga__( 'Otro', 'Beste bat' ), - ); -} - -add_shortcode( 'ga_contacto', function () { - $status = isset( $_GET['enviado'] ) ? sanitize_key( $_GET['enviado'] ) : ''; - $animal_id = isset( $_GET['adoptar'] ) ? absint( $_GET['adoptar'] ) : 0; - $animal = $animal_id && 'animal' === get_post_type( $animal_id ) ? get_the_title( $animal_id ) : ''; - $preselect = $animal ? 'adopcion' : ( isset( $_GET['motivo'] ) ? sanitize_key( $_GET['motivo'] ) : '' ); - $privacy = ga_page_url( 'politica-de-privacidad' ); - - ob_start(); - if ( 'ok' === $status ) { - echo '
' . esc_html( ga__( '¡Eskerrik asko!', 'Eskerrik asko!' ) ) . ' ' - . esc_html( ga__( 'Hemos recibido tu mensaje y te responderemos lo antes posible.', 'Zure mezua jaso dugu eta ahalik eta lasterren erantzungo dizugu.' ) ) . '
'; - } elseif ( 'error' === $status ) { - echo ''; - } - ?> -
- - - - - - -
- - -
-
- - -
- - - - -
- sanitize_text_field( wp_unslash( $_POST['nombre'] ?? '' ) ), - 'email' => sanitize_email( wp_unslash( $_POST['email'] ?? '' ) ), - 'telefono' => sanitize_text_field( wp_unslash( $_POST['telefono'] ?? '' ) ), - 'motivo' => $reasons[ $reason ] ?? $reasons['otro'], - 'animal' => sanitize_text_field( wp_unslash( $_POST['animal'] ?? '' ) ), - 'mensaje' => sanitize_textarea_field( wp_unslash( $_POST['mensaje'] ?? '' ) ), - 'idioma' => 'eu' === ( $_POST['idioma'] ?? '' ) ? 'Euskera' : 'Castellano', - ); - if ( ! $data['nombre'] || ! is_email( $data['email'] ) || ! $data['mensaje'] || empty( $_POST['privacidad'] ) ) { - $go( 'error' ); - } - - $subject = sprintf( '[Web] %s – %s', $data['motivo'], $data['nombre'] ); - if ( $data['animal'] ) { - $subject .= ' (' . $data['animal'] . ')'; - } - $body = sprintf( - "Nombre: %s\nEmail: %s\nTeléfono: %s\nMotivo: %s\nAnimal: %s\nIdioma: %s\n\n%s", - $data['nombre'], $data['email'], $data['telefono'] ?: '-', $data['motivo'], $data['animal'] ?: '-', $data['idioma'], $data['mensaje'] - ); - - // Se guarda siempre en el panel, aunque falle el correo. - wp_insert_post( array( - 'post_type' => 'ga_mensaje', - 'post_status' => 'private', - 'post_title' => $subject, - 'post_content' => $body, - ) ); - - wp_mail( ga_contact_email(), $subject, $body, array( 'Reply-To: ' . $data['nombre'] . ' <' . $data['email'] . '>' ) ); - - $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 ); - +require_once __DIR__ . '/gure-ametsa/i18n.php'; +require_once __DIR__ . '/gure-ametsa/animals.php'; +require_once __DIR__ . '/gure-ametsa/forms.php'; +require_once __DIR__ . '/gure-ametsa/api.php'; diff --git a/wp-content/mu-plugins/gure-ametsa/animals.php b/wp-content/mu-plugins/gure-ametsa/animals.php new file mode 100644 index 0000000..b09344a --- /dev/null +++ b/wp-content/mu-plugins/gure-ametsa/animals.php @@ -0,0 +1,519 @@ + array( + 'name' => 'Animales', + 'singular_name' => 'Animal', + 'add_new' => 'Añadir animal', + 'add_new_item' => 'Añadir nuevo animal', + 'edit_item' => 'Editar animal', + 'new_item' => 'Nuevo animal', + 'view_item' => 'Ver ficha', + 'search_items' => 'Buscar animales', + 'not_found' => 'No hay animales', + 'not_found_in_trash' => 'No hay animales en la papelera', + 'all_items' => 'Todos los animales', + 'featured_image' => 'Foto principal', + 'set_featured_image' => 'Elegir foto principal', + 'remove_featured_image' => 'Quitar foto principal', + 'use_featured_image' => 'Usar como foto principal', + 'excerpt' => 'Frase corta', + 'menu_name' => 'Animales', + ), + 'public' => true, + 'has_archive' => 'adopta', + 'rewrite' => array( 'slug' => 'adopta', 'with_front' => false ), + 'menu_icon' => 'dashicons-pets', + 'menu_position' => 5, + 'supports' => array( 'title', 'editor', 'thumbnail', 'excerpt' ), + 'show_in_rest' => true, + 'rest_base' => 'animales', + 'show_in_graphql' => true, + 'graphql_single_name' => 'animal', + 'graphql_plural_name' => 'animales', + ) ); + + register_taxonomy( 'especie', 'animal', array( + 'labels' => array( + 'name' => 'Especies', + 'singular_name' => 'Especie', + 'add_new_item' => 'Añadir especie', + ), + '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 ), + ) ); + + register_post_type( 'ga_mensaje', array( + 'labels' => array( + 'name' => 'Mensajes', + 'singular_name' => 'Mensaje', + 'edit_item' => 'Mensaje', + 'all_items' => 'Mensajes recibidos', + 'not_found' => 'Aún no hay mensajes', + ), + 'public' => false, + 'show_ui' => true, + 'menu_icon' => 'dashicons-email-alt', + 'menu_position' => 6, + 'supports' => array( 'title', 'editor' ), + 'capability_type' => 'post', + 'capabilities' => array( 'create_posts' => 'do_not_allow' ), + 'map_meta_cap' => true, + ) ); + + foreach ( array_keys( ga_fields() ) as $key ) { + register_post_meta( 'animal', "_ga_$key", array( + 'type' => 'string', + 'single' => true, + 'show_in_rest' => true, + 'auth_callback' => fn() => current_user_can( 'edit_posts' ), + ) ); + } +} ); + +/* ------------------------------------------------------------------------- + * Campos de la ficha + * + * 'shared' => true: el dato es común a la versión en castellano y en euskera. + * Los textos (carácter, necesidades…) se escriben en cada idioma. + * ---------------------------------------------------------------------- */ + +function ga_fields() { + return array( + 'estado' => array( 'shared' => true, 'label' => ga__( 'Estado', 'Egoera' ), 'type' => 'select', 'options' => array( + 'disponible' => ga__( 'Disponible', 'Eskuragarri' ), + 'proceso' => ga__( 'En proceso', 'Prozesuan' ), + 'adoptado' => ga__( 'Adoptado', 'Adoptatuta' ), + ), 'help' => 'Los adoptados salen solos del listado.' ), + 'destacado' => array( 'shared' => true, 'label' => ga__( 'Destacado', 'Nabarmendua' ), 'type' => 'checkbox', 'help' => 'Aparece en la portada. Útil para quien lleva más tiempo esperando o necesita un hogar especial.' ), + 'sexo' => array( 'shared' => true, 'label' => ga__( 'Sexo', 'Sexua' ), 'type' => 'select', 'options' => array( + 'macho' => ga__( 'Macho', 'Arra' ), + 'hembra' => ga__( 'Hembra', 'Emea' ), + ) ), + 'nacimiento' => array( 'shared' => true, 'label' => ga__( 'Fecha de nacimiento', 'Jaiotze-data' ), 'type' => 'date', 'help' => 'Si no se conoce, deja la fecha vacía y rellena la edad aproximada.' ), + 'edad' => array( 'shared' => true, 'label' => ga__( 'Edad aproximada', 'Gutxi gorabeherako adina' ), 'type' => 'number' ), + 'edad_unidad' => array( 'shared' => true, 'label' => ga__( 'Edad en', 'Adina' ), 'type' => 'select', 'options' => array( + 'anos' => ga__( 'Años', 'Urteak' ), + 'meses' => ga__( 'Meses', 'Hilabeteak' ), + ) ), + 'tamano' => array( 'shared' => true, 'label' => ga__( 'Tamaño', 'Tamaina' ), 'type' => 'select', 'options' => array( + 'pequeno' => ga__( 'Pequeño', 'Txikia' ), + 'mediano' => ga__( 'Mediano', 'Ertaina' ), + 'grande' => ga__( 'Grande', 'Handia' ), + ), 'help' => 'Solo en perros.' ), + 'llegada' => array( 'shared' => true, 'label' => ga__( 'En Bilagun desde', 'Bilagunen noiztik' ), 'type' => 'date', 'help' => 'Fecha de entrada, solo si está confirmada.' ), + 'galeria' => array( 'shared' => true, 'label' => ga__( 'Más fotos', 'Argazki gehiago' ), 'type' => 'gallery' ), + 'video' => array( 'shared' => true, 'label' => ga__( 'Vídeo', 'Bideoa' ), 'type' => 'url', 'help' => 'Enlace de YouTube, Vimeo o Instagram, o un vídeo subido a la biblioteca.' ), + + 'caracter' => array( 'label' => ga__( 'Cómo es', 'Nolakoa den' ), 'type' => 'textarea', 'help' => 'Su carácter, contado como en redes.' ), + 'necesidades' => array( 'label' => ga__( 'Qué necesita', 'Zer behar duen' ), 'type' => 'textarea' ), + 'convivencia' => array( 'label' => ga__( 'Convivencia con niños y otros animales', 'Haurrekin eta beste animaliekin bizikidetza' ), 'type' => 'textarea', 'help' => 'Solo lo observado, con contexto. Déjalo vacío si no lo sabemos.' ), + 'hogar' => array( 'label' => ga__( 'El hogar que buscamos', 'Bilatzen dugun etxea' ), 'type' => 'textarea' ), + ); +} + +function ga_get( $post_id, $key ) { + return (string) get_post_meta( $post_id, "_ga_$key", true ); +} + +/** Estado normalizado (acepta valores antiguos). */ +function ga_status( $post_id ) { + $estado = ga_get( $post_id, 'estado' ); + return match ( $estado ) { + 'adoptado' => 'adoptado', + 'proceso', 'reservado' => 'proceso', + default => 'disponible', + }; +} + +/** Etiqueta legible de un campo de opciones. */ +function ga_label( $post_id, $key ) { + $fields = ga_fields(); + $value = 'estado' === $key ? ga_status( $post_id ) : ga_get( $post_id, $key ); + if ( '' === $value || ! isset( $fields[ $key ] ) ) { + return ''; + } + $field = $fields[ $key ]; + if ( 'select' === $field['type'] ) { + return $field['options'][ $value ] ?? ''; + } + if ( 'date' === $field['type'] ) { + return date_i18n( get_option( 'date_format' ), strtotime( $value ) ); + } + return $value; +} + +/** Edad legible: calculada desde la fecha de nacimiento o la aproximada. */ +function ga_age( $post_id ) { + $birth = ga_get( $post_id, 'nacimiento' ); + if ( $birth && strtotime( $birth ) ) { + $diff = date_diff( date_create( $birth ), date_create( 'today' ) ); + $n = $diff->y ?: $diff->m; + $months = ! $diff->y; + if ( ! $n ) { + return ga__( 'Menos de un mes', 'Hilabete bat baino gutxiago' ); + } + } else { + $n = ga_get( $post_id, 'edad' ); + if ( '' === $n || ! is_numeric( $n ) ) { + return ''; + } + $n = (float) $n + 0; + $months = 'meses' === ga_get( $post_id, 'edad_unidad' ); + } + if ( 'eu' === ga_lang() ) { + return $n . ( $months ? ' hilabete' : ' urte' ); + } + if ( $months ) { + return $n . ( 1 == $n ? ' mes' : ' meses' ); + } + return $n . ( 1 == $n ? ' año' : ' años' ); +} + +/** ¿Es un perro? (el tamaño solo se muestra en perros) */ +function ga_is_dog( $post_id ) { + $terms = get_the_terms( $post_id, 'especie' ) ?: array(); + foreach ( $terms as $term ) { + if ( in_array( $term->slug, array( 'perro', 'txakurra' ), true ) ) { + return true; + } + } + return false; +} + +/** IDs de las fotos: la principal primero y después la galería. */ +function ga_gallery_ids( $post_id ) { + $ids = array_filter( array_map( 'absint', explode( ',', ga_get( $post_id, 'galeria' ) ) ) ); + if ( has_post_thumbnail( $post_id ) ) { + array_unshift( $ids, (int) get_post_thumbnail_id( $post_id ) ); + } + return array_values( array_unique( $ids ) ); +} + +/* ------------------------------------------------------------------------- + * Ficha en el panel + * ---------------------------------------------------------------------- */ + +/* Editor clásico para los animales: la historia arriba y la ficha justo debajo, siempre a la vista. */ +add_filter( 'use_block_editor_for_post_type', fn( $use, $type ) => 'animal' === $type ? false : $use, 10, 2 ); + +/* El cuadro de Yoast SEO va al final, debajo de la ficha. */ +add_filter( 'wpseo_metabox_prio', fn() => 'low' ); + +add_action( 'add_meta_boxes_animal', function () { + add_meta_box( 'ga_ficha', 'Ficha del animal', 'ga_render_metabox', 'animal', 'normal', 'high' ); +} ); + +function ga_render_metabox( $post ) { + wp_nonce_field( 'ga_ficha', 'ga_ficha_nonce' ); + $fields = ga_fields(); + $groups = array( + 'Datos (comunes a castellano y euskera)' => array_filter( $fields, fn( $f ) => ! empty( $f['shared'] ) ), + 'Textos de la ficha (en el idioma de esta página)' => array_filter( $fields, fn( $f ) => empty( $f['shared'] ) ), + ); + echo '

La historia se escribe en el editor principal. La «frase corta» (extracto) es opcional.

'; + foreach ( $groups as $title => $group ) { + echo '

' . esc_html( $title ) . '

'; + foreach ( $group as $key => $f ) { + $name = "ga_$key"; + $value = 'estado' === $key ? ga_status( $post->ID ) : ga_get( $post->ID, $key ); + echo ''; + } + echo ''; + } +} + +/* Selector de fotos de la galería */ +add_action( 'admin_enqueue_scripts', function ( $hook ) { + if ( ! in_array( $hook, array( 'post.php', 'post-new.php' ), true ) || 'animal' !== get_current_screen()->post_type ) { + return; + } + wp_enqueue_media(); + wp_add_inline_style( 'wp-admin', '.ga-gallery-admin{display:flex;flex-wrap:wrap;gap:8px;margin-bottom:8px}.ga-gallery-admin__item{position:relative;cursor:move}.ga-gallery-admin__item img{display:block;width:80px;height:80px;object-fit:cover;border-radius:6px}.ga-gallery-admin__item button{position:absolute;top:-6px;right:-6px;width:22px;height:22px;border-radius:50%;border:0;background:#b32d2e;color:#fff;cursor:pointer;line-height:1}' ); + wp_add_inline_script( 'media-editor', <<<'JS' +document.addEventListener('DOMContentLoaded', function () { + document.querySelectorAll('.ga-gallery-admin').forEach(function (box) { + var input = document.getElementById(box.dataset.input); + var sync = function () { + input.value = Array.from(box.querySelectorAll('[data-id]')).map(function (el) { return el.dataset.id; }).join(','); + }; + box.addEventListener('click', function (e) { + if (e.target.tagName === 'BUTTON') { e.target.parentNode.remove(); sync(); } + }); + box.nextElementSibling.addEventListener('click', function () { + var frame = wp.media({ title: 'Fotos del animal', multiple: 'add', library: { type: 'image' }, button: { text: 'Añadir a la ficha' } }); + frame.on('select', function () { + frame.state().get('selection').each(function (att) { + if (box.querySelector('[data-id="' + att.id + '"]')) return; + var src = (att.get('sizes') && att.get('sizes').thumbnail ? att.get('sizes').thumbnail.url : att.get('url')); + var item = document.createElement('span'); + item.className = 'ga-gallery-admin__item'; + item.dataset.id = att.id; + item.innerHTML = ''; + box.appendChild(item); + }); + sync(); + }); + frame.open(); + }); + }); +}); +JS + ); +} ); + +add_action( 'save_post_animal', function ( $post_id ) { + if ( ! isset( $_POST['ga_ficha_nonce'] ) || ! wp_verify_nonce( $_POST['ga_ficha_nonce'], 'ga_ficha' ) ) { + return; + } + if ( ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) || ! current_user_can( 'edit_post', $post_id ) ) { + return; + } + foreach ( ga_fields() as $key => $f ) { + $raw = wp_unslash( $_POST[ "ga_$key" ] ?? '' ); + $value = match ( $f['type'] ) { + 'select' => isset( $f['options'][ $raw ] ) ? $raw : '', + 'checkbox' => $raw ? '1' : '', + 'textarea' => sanitize_textarea_field( $raw ), + 'gallery' => implode( ',', array_filter( array_map( 'absint', explode( ',', $raw ) ) ) ), + 'url' => esc_url_raw( $raw ), + 'number' => '' === $raw ? '' : (string) absint( $raw ), + 'date' => preg_match( '/^\d{4}-\d{2}-\d{2}$/', $raw ) ? $raw : '', + default => sanitize_text_field( $raw ), + }; + if ( ! empty( $f['shared'] ) ) { + ga_update_meta_all_languages( $post_id, "_ga_$key", $value ); + } else { + update_post_meta( $post_id, "_ga_$key", $value ); + } + } +} ); + +/** Guarda un campo común en el animal y en todas sus traducciones. */ +function ga_update_meta_all_languages( $post_id, $meta_key, $value ) { + $ids = array( $post_id ); + if ( function_exists( 'pll_get_post_translations' ) ) { + $ids = array_unique( array_merge( $ids, array_values( pll_get_post_translations( $post_id ) ) ) ); + } + foreach ( $ids as $id ) { + update_post_meta( $id, $meta_key, $value ); + } +} + +/* Polylang: al crear o sincronizar traducciones, no copiar los textos (se escriben en cada idioma). */ +add_filter( 'pll_copy_post_metas', function ( $metas, $sync ) { + $texts = array_map( fn( $k ) => "_ga_$k", array_keys( array_filter( ga_fields(), fn( $f ) => empty( $f['shared'] ) ) ) ); + return $sync ? array_values( array_diff( $metas, $texts ) ) : $metas; +}, 10, 2 ); + +/* Columnas del listado del panel */ +add_filter( 'manage_animal_posts_columns', function ( $cols ) { + $new = array(); + foreach ( $cols as $k => $v ) { + if ( 'title' === $k ) { + $new['ga_foto'] = 'Foto'; + } + $new[ $k ] = $v; + if ( 'title' === $k ) { + $new['ga_estado'] = 'Estado'; + $new['ga_destacado'] = '★'; + } + } + return $new; +} ); + +add_action( 'manage_animal_posts_custom_column', function ( $col, $post_id ) { + if ( 'ga_foto' === $col ) { + echo get_the_post_thumbnail( $post_id, array( 60, 60 ) ); + } elseif ( 'ga_estado' === $col ) { + echo esc_html( ga_label( $post_id, 'estado' ) ); + } elseif ( 'ga_destacado' === $col ) { + echo ga_get( $post_id, 'destacado' ) ? '★' : ''; + } +}, 10, 2 ); + +/* Título de la pestaña del listado en el idioma actual */ +add_filter( 'document_title_parts', function ( $parts ) { + if ( is_post_type_archive( 'animal' ) ) { + $parts['title'] = ga__( 'Adopta', 'Adoptatu' ); + } + return $parts; +} ); + +/* ------------------------------------------------------------------------- + * Consultas + * ---------------------------------------------------------------------- */ + +/** meta_query de los estados visibles en los listados. */ +function ga_visible_meta_query() { + $hidden = array( 'adoptado' ); + if ( ! ga_setting( 'adopcion', 'show_in_process', true ) ) { + $hidden = array_merge( $hidden, array( 'proceso', 'reservado' ) ); + } + return array( + 'relation' => 'OR', + array( 'key' => '_ga_estado', 'value' => $hidden, 'compare' => 'NOT IN' ), + array( 'key' => '_ga_estado', 'compare' => 'NOT EXISTS' ), + ); +} + +/** Orden de los listados según el ajuste «Orden». */ +function ga_order_args() { + return 'antiguos' === ga_setting( 'adopcion', 'order', 'recientes' ) + ? array( 'orderby' => 'date', 'order' => 'ASC' ) + : array( 'orderby' => 'date', 'order' => 'DESC' ); +} + +add_action( 'pre_get_posts', function ( $q ) { + if ( is_admin() || ! $q->is_main_query() || ! ( $q->is_post_type_archive( 'animal' ) || $q->is_tax( 'especie' ) ) ) { + return; + } + $q->set( 'meta_query', array( ga_visible_meta_query() ) ); + $q->set( 'posts_per_page', 24 ); + foreach ( ga_order_args() as $k => $v ) { + $q->set( $k, $v ); + } +} ); + +/** + * Consulta reutilizable de animales (Polylang filtra por el idioma actual). + * + * @param array $args numero, especie (slugs), estado (lista o 'adoptado'), destacados (bool). + */ +function ga_query_animals( $args = array() ) { + $args = wp_parse_args( $args, array( 'numero' => 6, 'especie' => '', 'estado' => '', 'destacados' => false ) ); + $query = array( + 'post_type' => 'animal', + 'posts_per_page' => (int) $args['numero'], + 'no_found_rows' => true, + ) + ga_order_args(); + + if ( $args['especie'] ) { + $query['tax_query'] = array( array( + 'taxonomy' => 'especie', + 'field' => 'slug', + 'terms' => array_map( 'trim', explode( ',', $args['especie'] ) ), + ) ); + } + $meta = array(); + if ( $args['estado'] ) { + $meta[] = array( 'key' => '_ga_estado', 'value' => array_map( 'trim', explode( ',', $args['estado'] ) ), 'compare' => 'IN' ); + } else { + $meta[] = ga_visible_meta_query(); + } + if ( $args['destacados'] ) { + $meta[] = array( 'key' => '_ga_destacado', 'value' => '1' ); + } + $query['meta_query'] = $meta; + + $q = new WP_Query( $query ); + // Si no hay destacados marcados, se muestran los que llevan más tiempo esperando. + if ( $args['destacados'] && ! $q->have_posts() ) { + unset( $query['meta_query'][1] ); + $query['orderby'] = 'date'; + $query['order'] = 'ASC'; + $q = new WP_Query( $query ); + } + return $q; +} + +/* [ga_animales numero="6" especie="perro" destacados="1" vista="carrusel"] */ +add_shortcode( 'ga_animales', function ( $atts ) { + $atts = shortcode_atts( array( 'numero' => 6, 'especie' => '', 'estado' => '', 'destacados' => '', 'vista' => 'rejilla' ), $atts, 'ga_animales' ); + $atts['destacados'] = in_array( $atts['destacados'], array( '1', 'si', 'true' ), true ); + $q = ga_query_animals( $atts ); + ob_start(); + if ( $q->have_posts() ) { + $carousel = 'carrusel' === $atts['vista']; + $carousel ? ga_carousel_open() : print( '
' ); + while ( $q->have_posts() ) { + $q->the_post(); + ga_animal_card(); + } + $carousel ? ga_carousel_close() : print( '
' ); + } else { + echo '

' . esc_html( ga__( 'Ahora mismo no hay animales en esta sección. ¡Vuelve pronto!', 'Une honetan ez dago animaliarik atal honetan. Itzuli laster!' ) ) . '

'; + } + wp_reset_postdata(); + return ob_get_clean(); +} ); + +/** Apertura y cierre de un carrusel accesible (el tema aporta el CSS y el JS). */ +function ga_carousel_open( $label = '' ) { + printf( + '', + esc_attr( ga__( 'Anteriores', 'Aurrekoak' ) ), + esc_attr( ga__( 'Siguientes', 'Hurrengoak' ) ) + ); +} + +/** Tarjeta de un animal (dentro del loop). El tema la define en template-parts/animal-card.php. */ +function ga_animal_card() { + if ( locate_template( 'template-parts/animal-card.php' ) ) { + get_template_part( 'template-parts/animal-card' ); + return; + } + printf( '
%s
', esc_url( get_permalink() ), esc_html( get_the_title() ) ); +} diff --git a/wp-content/mu-plugins/gure-ametsa/api.php b/wp-content/mu-plugins/gure-ametsa/api.php new file mode 100644 index 0000000..269e06f --- /dev/null +++ b/wp-content/mu-plugins/gure-ametsa/api.php @@ -0,0 +1,113 @@ + 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/): 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/mu-plugins/gure-ametsa/forms.php b/wp-content/mu-plugins/gure-ametsa/forms.php new file mode 100644 index 0000000..3f26be6 --- /dev/null +++ b/wp-content/mu-plugins/gure-ametsa/forms.php @@ -0,0 +1,178 @@ + ga__( 'Adopción', 'Adopzioa' ), + 'acogida' => ga__( 'Casa de acogida', 'Harrera-etxea' ), + 'voluntario' => ga__( 'Voluntariado', 'Boluntariotza' ), + 'material' => ga__( 'Ayuda material', 'Laguntza materiala' ), + 'otro' => ga__( 'Otro', 'Beste bat' ), + ); +} + +/** Texto de confirmación tras enviar. */ +function ga_confirmation_text( $is_animal ) { + return $is_animal + ? ga_setting( 'adopcion', 'confirm', ga__( 'Hemos recibido tu solicitud. Nos pondremos en contacto contigo para enviarte nuestro cuestionario y conoceros un poquito mejor.', 'Zure eskaera jaso dugu. Zurekin harremanetan jarriko gara gure galdetegia bidaltzeko eta elkar hobeto ezagutzeko.' ) ) + : ga_setting( 'adopcion', 'confirm_contact', ga__( '¡Gracias! Hemos recibido tu mensaje y te responderemos lo antes posible.', 'Eskerrik asko! Zure mezua jaso dugu eta ahalik eta lasterren erantzungo dizugu.' ) ); +} + +/** + * [ga_contacto] formulario general. + * [ga_contacto animal="123"] formulario breve «Quiero conocerlo/la» (el animal va incluido). + */ +add_shortcode( 'ga_contacto', function ( $atts ) { + $atts = shortcode_atts( array( 'animal' => 0 ), $atts, 'ga_contacto' ); + $animal_id = absint( $atts['animal'] ) ?: absint( $_GET['adoptar'] ?? 0 ); + $animal_id = $animal_id && 'animal' === get_post_type( $animal_id ) ? $animal_id : 0; + $is_animal = absint( $atts['animal'] ) > 0; // Formulario breve dentro de la ficha. + $status = sanitize_key( $_GET['enviado'] ?? '' ); + $preselect = $animal_id ? 'adopcion' : sanitize_key( $_GET['motivo'] ?? '' ); + $privacy = ga_page_url( 'politica-de-privacidad' ); + $anchor = $is_animal ? 'conocer' : 'formulario'; + + ob_start(); + if ( 'ok' === $status ) { + echo '
' . esc_html( ga_confirmation_text( (bool) $animal_id ) ) . '
'; + if ( $is_animal ) { + return ob_get_clean(); + } + } elseif ( 'error' === $status ) { + echo ''; + } + ?> +
+ + + + + + + + + +
+ + +
+
+ + + + +
+ +

+ + + + +
+ sanitize_text_field( wp_unslash( $_POST['nombre'] ?? '' ) ), + 'email' => sanitize_email( wp_unslash( $_POST['email'] ?? '' ) ), + 'telefono' => sanitize_text_field( wp_unslash( $_POST['telefono'] ?? '' ) ), + 'motivo' => $reasons[ $reason ] ?? $reasons['otro'], + 'mensaje' => sanitize_textarea_field( wp_unslash( $_POST['mensaje'] ?? '' ) ), + 'idioma' => 'eu' === ( $_POST['idioma'] ?? '' ) ? 'Euskera' : 'Castellano', + ); + $message_required = ! $animal; + if ( ! $data['nombre'] || ! is_email( $data['email'] ) || ( $message_required && ! $data['mensaje'] ) || empty( $_POST['privacidad'] ) ) { + $go( 'error' ); + } + + $subject = $animal + ? sprintf( '[Web] Quiero conocer a %s – %s', $animal, $data['nombre'] ) + : sprintf( '[Web] %s – %s', $data['motivo'], $data['nombre'] ); + $body = sprintf( + "Nombre: %s\nEmail: %s\nTeléfono: %s\nMotivo: %s\nAnimal: %s\nIdioma: %s\n\n%s", + $data['nombre'], $data['email'], $data['telefono'] ?: '-', $data['motivo'], + $animal ? $animal . ' — ' . get_permalink( $animal_id ) : '-', + $data['idioma'], $data['mensaje'] ?: '(sin mensaje)' + ); + + // Se guarda siempre en el panel, aunque falle el correo. + wp_insert_post( array( + 'post_type' => 'ga_mensaje', + 'post_status' => 'private', + 'post_title' => $subject, + 'post_content' => $body, + ) ); + wp_mail( ga_contact_email(), $subject, $body, array( 'Reply-To: ' . $data['nombre'] . ' <' . $data['email'] . '>' ) ); + + $go( 'ok' ); +} + +/* [ga_necesidades] lista de ayuda material (se edita en Personalizar → Colabora) */ +add_shortcode( 'ga_necesidades', function () { + $items = array_filter( array_map( 'trim', explode( "\n", (string) ga_setting( 'material', 'list', '' ) ) ) ); + $note = ga_setting( 'material', 'note', '' ); + ob_start(); + if ( $items ) { + echo ''; + } + if ( $note ) { + echo '

' . esc_html( $note ) . '

'; + } + return ob_get_clean(); +} ); + +/* [ga_cita] aviso de cita previa */ +add_shortcode( 'ga_cita', function () { + $text = ga_info( 'cita' ); + return $text ? '

' . esc_html( $text ) . '

' : ''; +} ); diff --git a/wp-content/mu-plugins/gure-ametsa/i18n.php b/wp-content/mu-plugins/gure-ametsa/i18n.php new file mode 100644 index 0000000..d09f807 --- /dev/null +++ b/wp-content/mu-plugins/gure-ametsa/i18n.php @@ -0,0 +1,118 @@ +ID; + if ( function_exists( 'pll_get_post' ) ) { + $id = pll_get_post( $id, ga_lang() ) ?: $id; + } + return get_permalink( $id ) . $fragment; +} + +/** URL del listado de una especie (slug en castellano: perro, gato) en el idioma actual. */ +function ga_species_url( $slug_es ) { + $term = get_term_by( 'slug', $slug_es, 'especie' ); + if ( $term && function_exists( 'pll_get_term' ) ) { + $translated = pll_get_term( $term->term_id, ga_lang() ); + $term = $translated ? get_term( $translated, 'especie' ) : $term; + } + $url = $term && ! is_wp_error( $term ) ? get_term_link( $term ) : ''; + return is_wp_error( $url ) || ! $url ? get_post_type_archive_link( 'animal' ) : $url; +} + +/* Animales y especies son traducibles; los mensajes no. */ +add_filter( 'pll_get_post_types', function ( $types ) { + $types['animal'] = 'animal'; + unset( $types['ga_mensaje'] ); + return $types; +} ); + +add_filter( 'pll_get_taxonomies', function ( $taxonomies ) { + $taxonomies['especie'] = 'especie'; + return $taxonomies; +} ); + +/** + * Ajuste del personalizador del tema, con valor por defecto si el tema no está activo. + */ +function ga_setting( $section, $field, $default = '' ) { + if ( function_exists( 'ga_opt' ) ) { + $value = ga_opt( $section, $field ); + return null === $value ? $default : $value; + } + return $default; +} + +/* ------------------------------------------------------------------------- + * Datos de la protectora (el tema los sustituye por los del personalizador) + * ---------------------------------------------------------------------- */ + +function ga_info( $key = null ) { + $info = apply_filters( 'ga_info', array( + 'nombre' => 'Bilagun', + 'direccion' => 'Jaizubia, 44 · 20280 Hondarribia (Gipuzkoa)', + 'telefono' => '943 64 52 79', + 'email' => 'hola@gureametsabilagun.org', + 'horario' => ga__( 'Lunes a viernes: 10:00–13:00 y 14:00–19:00', 'Astelehenetik ostiralera: 10:00–13:00 eta 14:00–19:00' ), + 'cita' => ga__( 'Atendemos con cita previa. Escríbenos o llámanos antes de venir.', 'Aurretiko hitzorduarekin artatzen dugu. Idatzi edo deitu iezaguzu etorri aurretik.' ), + 'instagram' => 'https://www.instagram.com/gureametsabilagun/', + 'facebook' => 'https://www.facebook.com/gureametsabilagun/', + 'maps' => 'https://www.google.com/maps/search/?api=1&query=Jaizubia+44+Hondarribia', + ) ); + return $key ? ( $info[ $key ] ?? '' ) : $info; +} + +/** Correo que recibe los formularios: ajuste del panel → variable GA_CONTACT_EMAIL → administrador. */ +function ga_contact_email() { + $email = ga_setting( 'adopcion', 'form_email', '' ); + if ( ! is_email( $email ) ) { + $email = getenv( 'GA_CONTACT_EMAIL' ); + } + return is_email( $email ) ? $email : get_option( 'admin_email' ); +} diff --git a/wp-content/themes/gure-ametsa/404.php b/wp-content/themes/gure-ametsa/404.php index 6b242de..c689d83 100644 --- a/wp-content/themes/gure-ametsa/404.php +++ b/wp-content/themes/gure-ametsa/404.php @@ -3,12 +3,12 @@ get_header(); ?>
- +

- +

diff --git a/wp-content/themes/gure-ametsa/archive-animal.php b/wp-content/themes/gure-ametsa/archive-animal.php index 3ff9aee..3377b1d 100644 --- a/wp-content/themes/gure-ametsa/archive-animal.php +++ b/wp-content/themes/gure-ametsa/archive-animal.php @@ -1,98 +1,60 @@ 'especie', 'hide_empty' => false ) ); -$params = array_filter( array( - 'tamano' => sanitize_key( (string) get_query_var( 'tamano' ) ), - 'sexo' => sanitize_key( (string) get_query_var( 'sexo' ) ), - 'edad' => sanitize_key( (string) get_query_var( 'edad' ) ), - 'con' => sanitize_key( (string) get_query_var( 'con' ) ), -) ); - -/** Chip que activa o desactiva un filtro manteniendo el resto. */ -$chip = function ( $key, $value, $label ) use ( $params, $here ) { - $active = ( $params[ $key ] ?? '' ) === $value; - $args = $params; - if ( $active ) { - unset( $args[ $key ] ); - } else { - $args[ $key ] = $value; - } - printf( - '%s', - $active ? ' is-active' : '', - esc_url( add_query_arg( $args, $here ) ), - $active ? ' aria-current="true"' : '', - esc_html( $label ) - ); -}; - -$groups = array( - 'tamano' => array( $fields['tamano']['label'], $fields['tamano']['options'] ), - 'edad' => array( ga__( 'Edad', 'Adina' ), ga_age_groups() ), - 'sexo' => array( $fields['sexo']['label'], $fields['sexo']['options'] ), - 'con' => array( $fields['compatible']['label'], $fields['compatible']['options'] ), +$current = is_tax( 'especie' ) ? get_queried_object() : null; +$tiles = ! $current && 'tiles' === ga_opt( 'adopcion', 'archive_mode' ); +$groups = array( + 'perro' => array( ga_opt( 'adopcion', 'dog_label' ), (int) ga_opt( 'adopcion', 'dog_image' ), 'dog' ), + 'gato' => array( ga_opt( 'adopcion', 'cat_label' ), (int) ga_opt( 'adopcion', 'cat_image' ), 'cat' ), ); - -$title = $current - ? ga__( ga_plural( $current->name ) . ' en adopción', ga_plural( $current->name ) . ' adopzioan' ) - : ga__( 'Animales en adopción', 'Animaliak adopzioan' ); +$title = $current ? $current->name : ga__( 'Adopta', 'Adoptatu' ); +if ( $current ) { + $title = ga_plural( $current->name ); +} ?>
- +

-

+ +

+
-
-
-
- -
- - term_id === $term->term_id; ?> - name ) ); ?> - -
-
- [ $label, $options ] ) : ?> -
- -
- $option ) : ?> - - -
-
+ + + + + +
+ [ $label, $image, $class ] ) : ?> + + + '' ) ); ?> + + + + +
- -
- - +
'←', 'next_text' => '→' ) ); ?> -

+

-
-
-

-

-
- -
+
diff --git a/wp-content/themes/gure-ametsa/assets/js/main.js b/wp-content/themes/gure-ametsa/assets/js/main.js index 39921d2..7b71f51 100644 --- a/wp-content/themes/gure-ametsa/assets/js/main.js +++ b/wp-content/themes/gure-ametsa/assets/js/main.js @@ -62,3 +62,24 @@ update(); } ); } )(); + +// Ficha: miniaturas de la galería y copiar enlace. +( function () { + var main = document.querySelector( '[data-ga-gallery-main] img' ); + document.querySelectorAll( '.ga-thumbs button' ).forEach( function ( btn ) { + btn.addEventListener( 'click', function () { + if ( ! main ) { return; } + main.src = btn.dataset.full; + main.removeAttribute( 'srcset' ); + document.querySelectorAll( '.ga-thumbs button' ).forEach( function ( b ) { b.removeAttribute( 'aria-current' ); } ); + btn.setAttribute( 'aria-current', 'true' ); + } ); + } ); + document.querySelectorAll( '[data-copy]' ).forEach( function ( btn ) { + btn.addEventListener( 'click', function () { + if ( navigator.clipboard ) { + navigator.clipboard.writeText( btn.dataset.copy ).then( function () { btn.textContent = btn.dataset.done; } ); + } + } ); + } ); +} )(); diff --git a/wp-content/themes/gure-ametsa/footer.php b/wp-content/themes/gure-ametsa/footer.php index 6ba1660..7cb1f2b 100644 --- a/wp-content/themes/gure-ametsa/footer.php +++ b/wp-content/themes/gure-ametsa/footer.php @@ -1,17 +1,19 @@ array( - ga__( 'Animales disponibles', 'Animalia eskuragarriak' ) => get_post_type_archive_link( 'animal' ), - ga__( 'Cómo adoptar', 'Nola adoptatu' ) => $colabora . '#adopcion', - ga__( 'Quiénes somos', 'Nor gara' ) => ga_page_url( 'quienes-somos' ), - ga__( 'Hotel para perros y gatos', 'Txakur eta katuentzako hotela' ) => ga_page_url( 'hotel' ), + ga__( 'Adopta', 'Adoptatu' ) => array( + ga__( 'Perros', 'Txakurrak' ) => ga_species_url( 'perro' ), + ga__( 'Gatos', 'Katuak' ) => ga_species_url( 'gato' ), + ga__( 'Acoge', 'Harrera' ) => ga_page_url( 'acoge' ), ), - ga__( 'Colabora', 'Lagundu' ) => array( - ga__( 'Casa de acogida', 'Harrera-etxea' ) => $colabora . '#acogida', - ga__( 'Voluntariado', 'Boluntariotza' ) => $colabora . '#voluntariado', - ga__( 'Donaciones', 'Dohaintzak' ) => $colabora . '#donaciones', - ga__( 'Contacto', 'Harremanetarako' ) => ga_page_url( 'contacto' ), + ga__( 'Colabora', 'Lagundu' ) => array( + ga__( 'Voluntariado', 'Boluntariotza' ) => $colabora . '#voluntariado', + ga__( 'Ayuda material', 'Laguntza materiala' ) => $colabora . '#material', + ), + 'Bilagun' => array( + ga__( 'Quiénes somos', 'Nor gara' ) => ga_page_url( 'quienes-somos' ), + ga__( 'Preguntas frecuentes', 'Ohiko galderak' ) => ga_page_url( 'preguntas-frecuentes' ), + ga__( 'Contacto', 'Harremanetarako' ) => ga_page_url( 'contacto' ), ), ); ?> @@ -40,6 +42,9 @@ $columns = array(

diff --git a/wp-content/themes/gure-ametsa/template-parts/home/species.php b/wp-content/themes/gure-ametsa/template-parts/home/species.php index 5150f89..5197279 100644 --- a/wp-content/themes/gure-ametsa/template-parts/home/species.php +++ b/wp-content/themes/gure-ametsa/template-parts/home/species.php @@ -9,8 +9,8 @@ foreach ( array( 'dog' => 'perro', 'cat' => 'gato' ) as $key => $slug ) { } $tiles[ $key ] = array( 'url' => $term && ! is_wp_error( $term ) ? get_term_link( $term ) : get_post_type_archive_link( 'animal' ), - 'label' => ga_opt( 'species', "{$key}_label" ), - 'image' => (int) ga_opt( 'species', "{$key}_image" ), + 'label' => ga_opt( 'adopcion', "{$key}_label" ), + 'image' => (int) ga_opt( 'adopcion', "{$key}_image" ), ); } ?> @@ -25,7 +25,7 @@ foreach ( array( 'dog' => 'perro', 'cat' => 'gato' ) as $key => $slug ) { 'lazy', 'alt' => '' ) ); ?> - + diff --git a/wp-content/themes/gure-ametsa/template-parts/home/talk.php b/wp-content/themes/gure-ametsa/template-parts/home/talk.php index 45d3dba..799d820 100644 --- a/wp-content/themes/gure-ametsa/template-parts/home/talk.php +++ b/wp-content/themes/gure-ametsa/template-parts/home/talk.php @@ -1,7 +1,11 @@ +
-
+
+ +

+
  • @@ -9,17 +13,20 @@
  • Email
  • - -
  • - -
  • +
+ + +
+
-
-

- -
+ +
+

+ +
+
diff --git a/wp-content/themes/gure-ametsa/template-parts/home/visit.php b/wp-content/themes/gure-ametsa/template-parts/home/visit.php deleted file mode 100644 index 2e0fd42..0000000 --- a/wp-content/themes/gure-ametsa/template-parts/home/visit.php +++ /dev/null @@ -1,39 +0,0 @@ - -
-
- -
-
- - 'lazy' ) ); ?> - -
- -
-
-

-
    - -
  • - - -
  • - - -
  • - -
-
- - - - - - -
-
-
-
-