diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..55e0e07 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,4 @@ +.env +.git +*.md +docker-compose*.yml diff --git a/.env.example b/.env.example new file mode 100644 index 0000000..227805d --- /dev/null +++ b/.env.example @@ -0,0 +1,31 @@ +# URL pública del sitio (con https y sin barra final) +WP_URL=https://gureametsabilagun.eus +WP_TITLE=Gure Ametsa Bi Lagun + +# Administrador inicial de WordPress (solo se usa en la primera instalación) +WP_ADMIN_USER=gureametsa +WP_ADMIN_PASSWORD=cambia-esta-contraseña-larga +WP_ADMIN_EMAIL=hola@gureametsabilagun.org + +# Correo que recibe los mensajes del formulario de contacto / adopción +GA_CONTACT_EMAIL=hola@gureametsabilagun.org + +# Correo saliente (formularios, avisos) vía SMTP. Vacío = configurar desde el panel (WP Mail SMTP). +# Ejemplos: Gmail/Google Workspace → smtp.gmail.com, 587, tls (con contraseña de aplicación) +# Brevo → smtp-relay.brevo.com, 587, tls +SMTP_HOST= +SMTP_PORT=587 +SMTP_ENCRYPTION=tls +SMTP_USER= +SMTP_PASSWORD= +SMTP_FROM=hola@gureametsabilagun.org + +# Base de datos +DB_NAME=wordpress +DB_USER=wordpress +DB_PASSWORD=cambia-esto +DB_ROOT_PASSWORD=cambia-esto-tambien +DB_TABLE_PREFIX=ga_ + +# true = crea 4 animales de ejemplo en la primera instalación (útil para probar) +SEED_DEMO_ANIMALS=false diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..3323b34 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +.env +.DS_Store diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..fa294df --- /dev/null +++ b/Dockerfile @@ -0,0 +1,32 @@ +FROM wordpress:php8.3-apache + +# Cliente MariaDB (para `wp db export/import`) y utilidades +RUN apt-get update \ + && apt-get install -y --no-install-recommends mariadb-client less unzip \ + && rm -rf /var/lib/apt/lists/* + +# WP-CLI +RUN curl -fsSL -o /usr/local/bin/wp https://raw.githubusercontent.com/wp-cli/builds/gh-pages/phar/wp-cli.phar \ + && chmod +x /usr/local/bin/wp + +# Polylang (castellano / euskera) incluido en la imagen +ARG POLYLANG_VERSION=3.8.9 +RUN mkdir -p /usr/src/gure-ametsa/plugins \ + && curl -fsSL -o /tmp/polylang.zip "https://downloads.wordpress.org/plugin/polylang.${POLYLANG_VERSION}.zip" \ + && unzip -q /tmp/polylang.zip -d /usr/src/gure-ametsa/plugins \ + && rm /tmp/polylang.zip + +COPY docker/php.ini /usr/local/etc/php/conf.d/zz-gure-ametsa.ini + +# Código propio: se sincroniza dentro del volumen en cada arranque +COPY wp-content/themes/gure-ametsa /usr/src/gure-ametsa/themes/gure-ametsa +COPY wp-content/mu-plugins /usr/src/gure-ametsa/mu-plugins +COPY docker/content /usr/src/gure-ametsa/content +COPY docker/setup-content.php /usr/src/gure-ametsa/setup-content.php + +COPY docker/entrypoint.sh /usr/local/bin/ga-entrypoint.sh +COPY docker/setup.sh /usr/local/bin/ga-setup.sh +RUN chmod +x /usr/local/bin/ga-entrypoint.sh /usr/local/bin/ga-setup.sh + +ENTRYPOINT ["ga-entrypoint.sh"] +CMD ["apache2-foreground"] diff --git a/docker-compose.local.yml b/docker-compose.local.yml new file mode 100644 index 0000000..7ec9901 --- /dev/null +++ b/docker-compose.local.yml @@ -0,0 +1,7 @@ +# Solo para desarrollo local: +# docker compose -f docker-compose.yml -f docker-compose.local.yml up --build +# y abre http://localhost:8080 +services: + wordpress: + ports: + - "8080:80" diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..05f23a1 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,90 @@ +# Gure Ametsa Bi Lagun — WordPress para Dokploy (Docker Compose) +# +# En Dokploy: crea un servicio "Compose", apunta a este repositorio, +# define las variables de .env.example en la pestaña "Environment" y +# añade el dominio en "Domains" (servicio: wordpress, puerto: 80). + +services: + wordpress: + build: . + image: gure-ametsa-wordpress:latest + restart: unless-stopped + init: true + depends_on: + db: + condition: service_healthy + expose: + - "80" + environment: + WORDPRESS_DB_HOST: db + WORDPRESS_DB_NAME: ${DB_NAME:-wordpress} + WORDPRESS_DB_USER: ${DB_USER:-wordpress} + WORDPRESS_DB_PASSWORD: ${DB_PASSWORD:?Define DB_PASSWORD} + WORDPRESS_TABLE_PREFIX: ${DB_TABLE_PREFIX:-ga_} + WP_URL: ${WP_URL:?Define WP_URL (p. ej. https://gureametsabilagun.eus)} + WP_TITLE: ${WP_TITLE:-Gure Ametsa Bi Lagun} + WP_ADMIN_USER: ${WP_ADMIN_USER:-admin} + WP_ADMIN_PASSWORD: ${WP_ADMIN_PASSWORD:?Define WP_ADMIN_PASSWORD} + WP_ADMIN_EMAIL: ${WP_ADMIN_EMAIL:?Define WP_ADMIN_EMAIL} + GA_CONTACT_EMAIL: ${GA_CONTACT_EMAIL:-hola@gureametsabilagun.org} + SEED_DEMO_ANIMALS: ${SEED_DEMO_ANIMALS:-false} + SMTP_HOST: ${SMTP_HOST:-} + SMTP_PORT: ${SMTP_PORT:-587} + SMTP_ENCRYPTION: ${SMTP_ENCRYPTION:-tls} + SMTP_USER: ${SMTP_USER:-} + SMTP_PASSWORD: ${SMTP_PASSWORD:-} + SMTP_FROM: ${SMTP_FROM:-} + WORDPRESS_CONFIG_EXTRA: | + if ( getenv('WP_URL') ) { + define( 'WP_HOME', rtrim( getenv('WP_URL'), '/' ) ); + define( 'WP_SITEURL', rtrim( getenv('WP_URL'), '/' ) ); + } + define( 'FS_METHOD', 'direct' ); + define( 'DISALLOW_FILE_EDIT', true ); + define( 'WP_POST_REVISIONS', 10 ); + define( 'WP_AUTO_UPDATE_CORE', 'minor' ); + // Correo por SMTP (plugin WP Mail SMTP) si se definen las variables SMTP_* + if ( getenv('SMTP_HOST') ) { + define( 'WPMS_ON', true ); + define( 'WPMS_MAILER', 'smtp' ); + define( 'WPMS_SMTP_HOST', getenv('SMTP_HOST') ); + define( 'WPMS_SMTP_PORT', (int) ( getenv('SMTP_PORT') ?: 587 ) ); + define( 'WPMS_SSL', getenv('SMTP_ENCRYPTION') === 'none' ? '' : ( getenv('SMTP_ENCRYPTION') ?: 'tls' ) ); + define( 'WPMS_SMTP_AUTH', true ); + define( 'WPMS_SMTP_AUTOTLS', true ); + define( 'WPMS_SMTP_USER', getenv('SMTP_USER') ); + define( 'WPMS_SMTP_PASS', getenv('SMTP_PASSWORD') ); + define( 'WPMS_MAIL_FROM', getenv('SMTP_FROM') ?: getenv('SMTP_USER') ); + define( 'WPMS_MAIL_FROM_FORCE', true ); + define( 'WPMS_MAIL_FROM_NAME', 'Gure Ametsa Bi Lagun' ); + define( 'WPMS_MAIL_FROM_NAME_FORCE', true ); + } + volumes: + - wp_data:/var/www/html + healthcheck: + test: ["CMD-SHELL", "curl -fsS -o /dev/null -H 'X-Forwarded-Proto: https' http://localhost/wp-includes/images/blank.gif || exit 1"] + interval: 30s + timeout: 5s + retries: 5 + start_period: 60s + + db: + image: mariadb:11.4 + restart: unless-stopped + environment: + MARIADB_DATABASE: ${DB_NAME:-wordpress} + MARIADB_USER: ${DB_USER:-wordpress} + MARIADB_PASSWORD: ${DB_PASSWORD:?Define DB_PASSWORD} + MARIADB_ROOT_PASSWORD: ${DB_ROOT_PASSWORD:?Define DB_ROOT_PASSWORD} + volumes: + - db_data:/var/lib/mysql + healthcheck: + test: ["CMD", "healthcheck.sh", "--connect", "--innodb_initialized"] + interval: 10s + timeout: 5s + retries: 10 + start_period: 30s + +volumes: + wp_data: + db_data: diff --git a/docker/content/es/aviso-legal.html b/docker/content/es/aviso-legal.html new file mode 100644 index 0000000..00c7a8d --- /dev/null +++ b/docker/content/es/aviso-legal.html @@ -0,0 +1,11 @@ + +

Texto base: complétalo con la razón social y el CIF de la entidad y revísalo con vuestra asesoría.

+ + + +

En cumplimiento de la Ley 34/2002 de Servicios de la Sociedad de la Información (LSSI-CE), se informa de que este sitio web pertenece a Gure Ametsa Bi Lagun, con domicilio en Jaizubia, 44 · 20280 Hondarribia (Gipuzkoa). Contacto: hola@gureametsabilagun.org · 943 64 52 79.

+ + + +

Los textos e imágenes de esta web pertenecen a Gure Ametsa Bi Lagun y no pueden reproducirse sin autorización, salvo para difundir a los animales en adopción citando la fuente.

+ diff --git a/docker/content/es/colabora.html b/docker/content/es/colabora.html new file mode 100644 index 0000000..5cdf1ca --- /dev/null +++ b/docker/content/es/colabora.html @@ -0,0 +1,63 @@ + +

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.

+ + + +

🦮 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.

+ + + +
+
Quiero colaborar
+
+ diff --git a/docker/content/es/contacto.html b/docker/content/es/contacto.html new file mode 100644 index 0000000..1372b74 --- /dev/null +++ b/docker/content/es/contacto.html @@ -0,0 +1,15 @@ + +

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

+ + + +

Escríbenos

+ + + +

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

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

¿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/inicio.html b/docker/content/es/inicio.html new file mode 100644 index 0000000..b12ead6 --- /dev/null +++ b/docker/content/es/inicio.html @@ -0,0 +1,7 @@ + +

Ongi etorri · Bienvenidos

+ + + +

Gure Ametsa Bi Lagun es la protectora y residencia de animales de Hondarribia. Desde hace más de 25 años colaboramos con los ayuntamientos de Irun y Hondarribia recogiendo a los animales perdidos o abandonados, dándoles atención veterinaria y cuidándolos hasta que encuentran una familia.

+ diff --git a/docker/content/es/privacidad.html b/docker/content/es/privacidad.html new file mode 100644 index 0000000..2256803 --- /dev/null +++ b/docker/content/es/privacidad.html @@ -0,0 +1,43 @@ + +

Texto base: revísalo con vuestra asesoría antes de publicar la web y completa los datos del responsable (razón social y CIF).

+ + + +

Responsable del tratamiento

+ + + +

Gure Ametsa Bi Lagun · Jaizubia, 44 · 20280 Hondarribia (Gipuzkoa) · hola@gureametsabilagun.org · 943 64 52 79.

+ + + +

Qué datos tratamos y para qué

+ + + +

Los datos que nos envías a través del formulario de contacto (nombre, email, teléfono y mensaje) se usan únicamente para responder a tu consulta y, en su caso, gestionar la adopción, acogida, voluntariado o reserva que solicites. La base legal es tu consentimiento.

+ + + +

Conservación y destinatarios

+ + + +

Conservamos los datos el tiempo necesario para atender tu solicitud y cumplir las obligaciones legales. No se ceden a terceros salvo obligación legal.

+ + + +

Tus derechos

+ + + +

Puedes ejercer tus derechos de acceso, rectificación, supresión, oposición, limitación y portabilidad escribiendo a hola@gureametsabilagun.org. También puedes reclamar ante la Agencia Española de Protección de Datos (www.aepd.es).

+ + + +

Cookies

+ + + +

Esta web solo utiliza cookies técnicas necesarias para su funcionamiento. No utilizamos cookies de analítica ni de publicidad.

+ diff --git a/docker/content/es/quienes-somos.html b/docker/content/es/quienes-somos.html new file mode 100644 index 0000000..1a9f132 --- /dev/null +++ b/docker/content/es/quienes-somos.html @@ -0,0 +1,43 @@ + +

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.

+ + + +

Nuestra labor

+ + + +

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.

+ + + +

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

+ + + + + + + +
+

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

+
+ + + +

¿Has perdido a tu animal?

+ + + +

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.

+ diff --git a/docker/content/eu/harremanetarako.html b/docker/content/eu/harremanetarako.html new file mode 100644 index 0000000..031503d --- /dev/null +++ b/docker/content/eu/harremanetarako.html @@ -0,0 +1,15 @@ + +

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

+ + + +

Idatzi iezaguzu

+ + + +

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

+ + + +[ga_contacto] + diff --git a/docker/content/eu/hasiera.html b/docker/content/eu/hasiera.html new file mode 100644 index 0000000..39d1b96 --- /dev/null +++ b/docker/content/eu/hasiera.html @@ -0,0 +1,7 @@ + +

Ongi etorri

+ + + +

Gure Ametsa Bi Lagun Hondarribiko animalien babesleku eta egoitza da. 25 urte baino gehiago daramatzagu Irun eta Hondarribiko udalekin lanean: galdutako edo abandonatutako animaliak jasotzen ditugu, albaitari-arreta ematen diegu eta familia bat aurkitu arte zaintzen ditugu.

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

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 new file mode 100644 index 0000000..bf67763 --- /dev/null +++ b/docker/content/eu/lagundu.html @@ -0,0 +1,63 @@ + +

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.

+ + + +

🦮 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.

+ + + +
+
Lagundu nahi dut
+
+ diff --git a/docker/content/eu/lege-oharra.html b/docker/content/eu/lege-oharra.html new file mode 100644 index 0000000..fc0aef5 --- /dev/null +++ b/docker/content/eu/lege-oharra.html @@ -0,0 +1,11 @@ + +

Oinarrizko testua: osatu erakundearen izen sozialarekin eta IFKarekin, eta berrikusi zuen aholkularitzarekin.

+ + + +

Informazio Gizartearen Zerbitzuei buruzko 34/2002 Legea (LSSI-CE) betez, jakinarazten da webgune hau Gure Ametsa Bi Lagun erakundearena dela, helbidea Jaizubia, 44 · 20280 Hondarribia (Gipuzkoa) duena. Harremanetarako: hola@gureametsabilagun.org · 943 64 52 79.

+ + + +

Webgune honetako testuak eta irudiak Gure Ametsa Bi Lagunenak dira eta ezin dira baimenik gabe erreproduzitu, adopzioko animaliak zabaltzeko izan ezik, iturria aipatuz gero.

+ diff --git a/docker/content/eu/nor-gara.html b/docker/content/eu/nor-gara.html new file mode 100644 index 0000000..2a0f567 --- /dev/null +++ b/docker/content/eu/nor-gara.html @@ -0,0 +1,43 @@ + +

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

+ + + +

Gure lana

+ + + +

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.

+ + + +

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

+ + + + + + + +
+

Adoptatu eta bi mundu aldatu: berea eta zurea.

+
+ + + +

Zure animalia galdu duzu?

+ + + +

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.

+ diff --git a/docker/content/eu/pribatutasun-politika.html b/docker/content/eu/pribatutasun-politika.html new file mode 100644 index 0000000..31a1631 --- /dev/null +++ b/docker/content/eu/pribatutasun-politika.html @@ -0,0 +1,43 @@ + +

Oinarrizko testua: berrikusi zuen aholkularitzarekin webgunea argitaratu aurretik eta osatu arduradunaren datuak (izen soziala eta IFK).

+ + + +

Tratamenduaren arduraduna

+ + + +

Gure Ametsa Bi Lagun · Jaizubia, 44 · 20280 Hondarribia (Gipuzkoa) · hola@gureametsabilagun.org · 943 64 52 79.

+ + + +

Zein datu tratatzen ditugu eta zertarako

+ + + +

Harremanetarako formularioaren bidez bidaltzen dizkiguzun datuak (izena, posta elektronikoa, telefonoa eta mezua) zure kontsultari erantzuteko eta, hala badagokio, eskatzen duzun adopzioa, harrera, boluntariotza edo erreserba kudeatzeko baino ez dira erabiltzen. Oinarri juridikoa zure baimena da.

+ + + +

Kontserbazioa eta hartzaileak

+ + + +

Datuak zure eskaera artatzeko eta lege-betebeharrak betetzeko behar den denboran gordetzen ditugu. Ez zaizkie hirugarrenei lagatzen, legezko betebeharra dagoenean izan ezik.

+ + + +

Zure eskubideak

+ + + +

Datuetara sartzeko, zuzentzeko, ezabatzeko, aurka egiteko, mugatzeko eta eramateko eskubideak erabil ditzakezu hola@gureametsabilagun.org helbidera idatzita. Datuak Babesteko Espainiako Agentzian (www.aepd.es) ere erreklamazioa aurkez dezakezu.

+ + + +

Cookieak

+ + + +

Webgune honek funtzionatzeko beharrezkoak diren cookie teknikoak baino ez ditu erabiltzen. Ez dugu analitikarako edo publizitaterako cookierik erabiltzen.

+ diff --git a/docker/entrypoint.sh b/docker/entrypoint.sh new file mode 100644 index 0000000..c6cfa2a --- /dev/null +++ b/docker/entrypoint.sh @@ -0,0 +1,11 @@ +#!/bin/bash +# Envoltorio del entrypoint oficial de WordPress: +# lanza en segundo plano la configuración inicial (ga-setup.sh) y después +# arranca Apache con el entrypoint original. +set -euo pipefail + +if [[ "${1:-}" == apache2* ]]; then + ga-setup.sh & +fi + +exec docker-entrypoint.sh "$@" diff --git a/docker/php.ini b/docker/php.ini new file mode 100644 index 0000000..c642a9d --- /dev/null +++ b/docker/php.ini @@ -0,0 +1,5 @@ +upload_max_filesize = 64M +post_max_size = 64M +memory_limit = 256M +max_execution_time = 120 +expose_php = Off diff --git a/docker/setup-content.php b/docker/setup-content.php new file mode 100644 index 0000000..25f6b1f --- /dev/null +++ b/docker/setup-content.php @@ -0,0 +1,276 @@ +model; + $existing = wp_list_pluck( $model->get_languages_list(), 'slug' ); + $langs = 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() ); + } + } + $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' ), + ); + $options = PLL()->options; + if ( is_object( $options ) && method_exists( $options, 'set' ) ) { + foreach ( $settings as $key => $value ) { + $options->set( $key, $value ); + } + if ( method_exists( $options, 'save_all' ) ) { + $options->save_all(); + } + } 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 ); + $mo->add_entry( $mo->make_entry( get_option( 'blogdescription' ), 'Adoptatu eta bi mundu aldatu · Hondarribia' ) ); + $mo->export_to_db( $eu ); + } + 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; + } + $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() ); + } + if ( function_exists( 'pll_set_post_language' ) ) { + pll_set_post_language( $id, $lang ); + } + return $id; +} + +// slug es => [título es, archivo es, slug eu, título eu, archivo 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' ), +); + +$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' ); + if ( $pll ) { + $ids[ $slug ]['eu'] = ga_setup_page( $slug_eu, $title_eu, "$src/eu/$file_eu.html", 'eu' ); + pll_save_post_translations( $ids[ $slug ] ); + } +} + +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' ); + +/* ---------- 3. Especies ---------- */ +$species = array( + 'perro' => array( 'Perro', 'txakurra', 'Txakurra' ), + 'gato' => array( 'Gato', 'katua', 'Katua' ), + 'otros' => array( 'Otros', 'besteak', 'Besteak' ), +); +$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 ( $pairs as $lang => [ $term_slug, $term_name ] ) { + $term = get_term_by( 'slug', $term_slug, 'especie' ); + if ( ! $term ) { + $res = wp_insert_term( $term_name, 'especie', array( 'slug' => $term_slug ) ); + $term = is_wp_error( $res ) ? null : get_term( $res['term_id'], 'especie' ); + } + if ( $term ) { + $term_ids[ $slug ][ $lang ] = $term->term_id; + if ( $pll ) { + pll_set_term_language( $term->term_id, $lang ); + } + } + } + if ( $pll && count( $term_ids[ $slug ] ?? array() ) === 2 ) { + pll_save_term_translations( $term_ids[ $slug ] ); + } +} + +/* ---------- 4. Menús ---------- */ +function ga_setup_menu( $name, $items ) { + $menu = wp_get_nav_menu_object( $name ); + if ( $menu ) { + return $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'] ); + } + wp_update_nav_menu_item( $menu_id, 0, $args ); + } + return $menu_id; +} + +$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' => 'Contacto', 'page' => $ids['contacto']['es'] ), + ) ), + ), + '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'] ), + ) ), + ), +); +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' => 'Harremanetarako', 'page' => $ids['contacto']['eu'] ), + ) ); + $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'] ), + ) ); + + $theme = get_stylesheet(); + $nav_menus = array( $theme => $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' ) ) { + PLL()->options->save_all(); + } + } else { + $opts = (array) get_option( 'polylang', array() ); + $opts['nav_menus'] = $nav_menus; + 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' ); + +/* ---------- 5. Animales de ejemplo (opcional) ---------- */ +if ( 'true' === getenv( 'SEED_DEMO_ANIMALS' ) ) { + $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.' ), + 'sp' => 'perro', + 'meta' => array( 'sexo' => 'hembra', 'edad' => '3', 'edad_unidad' => 'anos', 'tamano' => 'mediano', 'estado' => 'disponible', 'raza' => 'Mestiza' ), + ), + 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.' ), + 'sp' => 'gato', + 'meta' => array( 'sexo' => 'macho', 'edad' => '1', 'edad_unidad' => 'anos', 'tamano' => 'pequeno', 'estado' => 'disponible', 'raza' => 'Común europeo' ), + ), + 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.' ), + 'sp' => 'perro', + 'meta' => array( 'sexo' => 'macho', 'edad' => '7', 'edad_unidad' => 'anos', 'tamano' => 'grande', 'estado' => 'urgente', 'raza' => 'Mastín' ), + ), + 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.' ), + 'sp' => 'gato', + 'meta' => array( 'sexo' => 'hembra', 'edad' => '4', 'edad_unidad' => 'meses', 'tamano' => 'pequeno', 'estado' => 'reservado', 'raza' => 'Común europeo' ), + ), + ); + foreach ( $demo as $animal ) { + $translations = array(); + foreach ( $pll ? array( 'es', 'eu' ) : array( 'es' ) as $lang ) { + [ $title, $text ] = $animal[ $lang ]; + $id = wp_insert_post( array( + 'post_type' => 'animal', + 'post_status' => 'publish', + 'post_title' => $title, + 'post_content' => "\n

$text

\n", + ) ); + 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 ) { + update_post_meta( $id, "_ga_$key", $value ); + } + if ( $pll ) { + pll_set_post_language( $id, $lang ); + } + $translations[ $lang ] = $id; + } + if ( $pll ) { + pll_save_post_translations( $translations ); + } + } + WP_CLI::log( '[ga-setup] Animales de ejemplo creados' ); +} + +// Polylang guarda en caché la portada de cada idioma: se regenera con las traducciones ya creadas. +if ( $pll ) { + PLL()->model->clean_languages_cache(); +} +flush_rewrite_rules( false ); diff --git a/docker/setup.sh b/docker/setup.sh new file mode 100644 index 0000000..815d2a4 --- /dev/null +++ b/docker/setup.sh @@ -0,0 +1,160 @@ +#!/bin/bash +# Configuración inicial idempotente de WordPress para Gure Ametsa Bi Lagun. +# Se ejecuta en segundo plano en cada arranque del contenedor. +set -uo pipefail + +log() { echo "[ga-setup] $*"; } + +WP_PATH=/var/www/html +SRC=/usr/src/gure-ametsa +export WP_CLI_CACHE_DIR=/tmp/wp-cli-cache + +wp_() { runuser -u www-data -- wp --path="$WP_PATH" "$@"; } + +# 1. Esperar a que el entrypoint oficial copie WordPress y genere wp-config.php +for _ in $(seq 1 120); do + [[ -f "$WP_PATH/wp-config.php" && -f "$WP_PATH/wp-includes/version.php" ]] && break + sleep 1 +done + +# 2. Sincronizar tema y mu-plugins propios (siempre, para que las actualizaciones de imagen se apliquen) +mkdir -p "$WP_PATH/wp-content/themes" "$WP_PATH/wp-content/mu-plugins" "$WP_PATH/wp-content/uploads" +rm -rf "$WP_PATH/wp-content/themes/gure-ametsa" +cp -r "$SRC/themes/gure-ametsa" "$WP_PATH/wp-content/themes/" +cp -r "$SRC/mu-plugins/." "$WP_PATH/wp-content/mu-plugins/" +# Polylang: se copia solo si no existe (después se actualiza desde el panel) +if [[ ! -d "$WP_PATH/wp-content/plugins/polylang" ]]; then + mkdir -p "$WP_PATH/wp-content/plugins" + cp -r "$SRC/plugins/polylang" "$WP_PATH/wp-content/plugins/" +fi +chown -R www-data:www-data "$WP_PATH/wp-content" +log "Tema y mu-plugins sincronizados" + +# .htaccess para enlaces permanentes bonitos +if [[ ! -f "$WP_PATH/.htaccess" ]]; then + cat > "$WP_PATH/.htaccess" <<'EOF' +# BEGIN WordPress + +RewriteEngine On +RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}] +RewriteBase / +RewriteRule ^index\.php$ - [L] +RewriteCond %{REQUEST_FILENAME} !-f +RewriteCond %{REQUEST_FILENAME} !-d +RewriteRule . /index.php [L] + +# END WordPress +EOF + chown www-data:www-data "$WP_PATH/.htaccess" +fi + +# 3. Esperar a la base de datos +for i in $(seq 1 60); do + if php -r ' + $h = getenv("WORDPRESS_DB_HOST") ?: "db"; $p = 3306; + if (strpos($h, ":") !== false) { [$h, $p] = explode(":", $h, 2); } + $m = @new mysqli($h, getenv("WORDPRESS_DB_USER"), getenv("WORDPRESS_DB_PASSWORD"), getenv("WORDPRESS_DB_NAME"), (int) $p); + exit($m->connect_errno ? 1 : 0);'; then + break + fi + [[ $i -eq 60 ]] && { log "La base de datos no responde; se aborta la configuración"; exit 1; } + sleep 2 +done + +# 4. Instalar WordPress si hace falta +if ! wp_ core is-installed 2>/dev/null; then + : "${WP_URL:?Falta WP_URL}" "${WP_ADMIN_USER:?Falta WP_ADMIN_USER}" "${WP_ADMIN_PASSWORD:?Falta WP_ADMIN_PASSWORD}" "${WP_ADMIN_EMAIL:?Falta WP_ADMIN_EMAIL}" + log "Instalando WordPress en $WP_URL" + wp_ core install \ + --url="$WP_URL" \ + --title="${WP_TITLE:-Gure Ametsa Bi Lagun}" \ + --admin_user="$WP_ADMIN_USER" \ + --admin_password="$WP_ADMIN_PASSWORD" \ + --admin_email="$WP_ADMIN_EMAIL" \ + --skip-email || { log "Fallo en la instalación"; exit 1; } +fi + +# 5. Configuración por etapas (cada etapa se ejecuta una sola vez) +VERSION=$(wp_ option get ga_setup_version 2>/dev/null || echo 0) +[[ "$VERSION" =~ ^[0-9]+$ ]] || VERSION=0 + +# Etapa 2: idiomas, tema, contenido inicial +if (( VERSION < 2 )); then + log "Configurando el sitio por primera vez" + + # Idiomas, zona horaria y ajustes generales + { wp_ language core install es_ES && wp_ site switch-language es_ES; } || log "No se pudo instalar es_ES (¿sin internet?)" + wp_ language core install eu || log "No se pudo instalar eu (¿sin internet?)" + wp_ option update blogdescription "Adopta y cambia dos mundos · Hondarribia" + wp_ option update timezone_string "Europe/Madrid" + wp_ option update start_of_week 1 + wp_ option update default_comment_status closed + wp_ option update default_ping_status closed + wp_ rewrite structure '/%postname%/' + + wp_ theme activate gure-ametsa + + # Limpiar contenido de ejemplo y extras + wp_ post delete 1 2 3 --force 2>/dev/null || true + wp_ plugin delete hello akismet 2>/dev/null || true + + # Polylang: web bilingüe castellano / euskera + wp_ plugin activate polylang || log "No se pudo activar Polylang: la web quedará solo en castellano" + 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 + log "Fallo creando el contenido inicial" + exit 1 + fi + + wp_ rewrite flush + wp_ option update ga_setup_version 2 +fi + +# Etapa 3: plugins recomendados +if (( VERSION < 3 )); then + log "Instalando plugins recomendados" + + # Activos desde el principio + ACTIVE=( + wp-mail-smtp # Envío de correo fiable (SMTP) + updraftplus # Copias de seguridad + limit-login-attempts-reloaded # Bloqueo de ataques al login + two-factor # Verificación en dos pasos + webp-converter-for-media # Fotos más ligeras (WebP) + wordpress-seo # Yoast SEO + 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=( + give # Donaciones online (GiveWP) + mailpoet # Newsletter + complianz-gdpr # Aviso de cookies (solo si se añaden cookies de terceros) + wp-super-cache # Caché de páginas + ) + + for plugin in "${ACTIVE[@]}"; do + wp_ plugin install "$plugin" --activate >/dev/null 2>&1 && log " ✓ $plugin" || log " ✗ No se pudo instalar $plugin" + done + for plugin in "${INACTIVE[@]}"; do + wp_ plugin install "$plugin" >/dev/null 2>&1 && log " ✓ $plugin (desactivado)" || log " ✗ No se pudo instalar $plugin" + done + wp_ language plugin install --all es_ES eu >/dev/null 2>&1 || true + # Sin pantallas de bienvenida de los plugins al entrar por primera vez al panel + wp_ transient delete --all >/dev/null 2>&1 || true + wp_ option delete sbi_plugin_do_activation_redirect >/dev/null 2>&1 || true + + # Copias de seguridad: base de datos a diario, archivos cada semana + wp_ option update updraft_interval weekly + wp_ option update updraft_interval_database daily + wp_ option update updraft_retain 4 + wp_ option update updraft_retain_db 14 + + wp_ option update ga_setup_version 3 +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 new file mode 100644 index 0000000..981d57c --- /dev/null +++ b/wp-content/mu-plugins/gure-ametsa-core.php @@ -0,0 +1,634 @@ +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, + ) ); + + 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, + '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' ); +} diff --git a/wp-content/themes/gure-ametsa/404.php b/wp-content/themes/gure-ametsa/404.php new file mode 100644 index 0000000..6b242de --- /dev/null +++ b/wp-content/themes/gure-ametsa/404.php @@ -0,0 +1,16 @@ + +
+
+ +

+

+

+ + +

+
+
+ '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'] ), +); + +$title = $current + ? ga__( ga_plural( $current->name ) . ' en adopción', ga_plural( $current->name ) . ' adopzioan' ) + : ga__( 'Animales en adopción', 'Animaliak adopzioan' ); +?> + +
+
+ +

+

+
+
+ +
+
+
+
+
+ +
+ + term_id === $term->term_id; ?> + name ) ); ?> + +
+
+ [ $label, $options ] ) : ?> +
+ +
+ $option ) : ?> + + +
+
+ +
+ +
+ + +
+ +
+ + +

+ + +
+
+

+

+
+ +
+
+
+ + diff --git a/wp-content/themes/gure-ametsa/assets/js/main.js b/wp-content/themes/gure-ametsa/assets/js/main.js new file mode 100644 index 0000000..39921d2 --- /dev/null +++ b/wp-content/themes/gure-ametsa/assets/js/main.js @@ -0,0 +1,64 @@ +( function () { + var toggle = document.querySelector( '.ga-menu-toggle' ); + var nav = document.getElementById( 'ga-nav' ); + if ( toggle && nav ) { + toggle.addEventListener( 'click', function () { + var open = nav.classList.toggle( 'is-open' ); + toggle.setAttribute( 'aria-expanded', open ? 'true' : 'false' ); + } ); + document.addEventListener( 'keydown', function ( e ) { + if ( e.key === 'Escape' && nav.classList.contains( 'is-open' ) ) { + nav.classList.remove( 'is-open' ); + toggle.setAttribute( 'aria-expanded', 'false' ); + toggle.focus(); + } + } ); + } + + // Filtros del listado: los