Web de Gure Ametsa Bi Lagun en WordPress para Dokploy

- Docker Compose (WordPress + MariaDB) listo para Dokploy, con instalación
  automática por etapas: idiomas, páginas, menús y plugins recomendados.
- Web bilingüe castellano / euskera con Polylang.
- Tema propio «gure-ametsa»: diseño inspirado en Beargrass Animal Rescue,
  personalizable desde Apariencia → Personalizar (paletas, tipografías,
  secciones de portada ordenables) y patrones de bloques propios.
- Plugin mu «gure-ametsa-core»: animales en adopción con ficha y filtros,
  carrusel y formulario de contacto/adopción.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-09-24 16:21:26 +02:00
parent 97b8c1be31
commit 0b2c9f271f
64 changed files with 4561 additions and 0 deletions

View File

@@ -0,0 +1,634 @@
<?php
/**
* Plugin Name: Gure Ametsa – Núcleo
* Description: Animales en adopción, fichas, listados y formulario de contacto/adopción de Gure Ametsa Bi Lagun. Bilingüe castellano/euskera (con Polylang).
* Version: 1.1.0
* Author: Gure Ametsa Bi Lagun
*/
defined( 'ABSPATH' ) || exit;
/* -------------------------------------------------------------------------
* Idioma (castellano / euskera)
* ---------------------------------------------------------------------- */
/** Idioma actual: 'es' o 'eu'. El panel de administración siempre en castellano. */
function ga_lang() {
if ( is_admin() && ! wp_doing_ajax() ) {
return 'es';
}
$lang = function_exists( 'pll_current_language' ) ? pll_current_language() : '';
return 'eu' === $lang ? 'eu' : 'es';
}
/** Devuelve el texto en el idioma actual. */
function ga__( $es, $eu ) {
return 'eu' === ga_lang() ? $eu : $es;
}
/** Imprime el texto escapado en el idioma actual. */
function ga_e( $es, $eu ) {
echo esc_html( ga__( $es, $eu ) );
}
/** URL de una página por su slug en castellano, en el idioma actual. */
function ga_page_url( $slug_es, $fragment = '' ) {
$page = get_page_by_path( $slug_es );
if ( ! $page ) {
return home_url( "/$slug_es/" ) . $fragment;
}
$id = $page->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 '<table class="form-table" role="presentation"><tbody>';
foreach ( ga_fields() as $key => $f ) {
$name = "ga_$key";
$value = ga_get( $post->ID, $key );
if ( 'estado' === $key && '' === $value ) {
$value = 'disponible';
}
echo '<tr><th scope="row"><label for="' . esc_attr( $name ) . '">' . esc_html( $f['label'] ) . '</label></th><td>';
switch ( $f['type'] ) {
case 'select':
echo '<select id="' . esc_attr( $name ) . '" name="' . esc_attr( $name ) . '"><option value="">—</option>';
foreach ( $f['options'] as $v => $l ) {
printf( '<option value="%s"%s>%s</option>', esc_attr( $v ), selected( $value, $v, false ), esc_html( $l ) );
}
echo '</select>';
break;
case 'checks':
$current = array_filter( explode( ',', $value ) );
foreach ( $f['options'] as $v => $l ) {
printf(
'<label style="margin-right:1em"><input type="checkbox" name="%s[]" value="%s"%s> %s</label>',
esc_attr( $name ), esc_attr( $v ), checked( in_array( $v, $current, true ), true, false ), esc_html( $l )
);
}
break;
default:
printf(
'<input type="%s" id="%s" name="%s" value="%s" class="%s" placeholder="%s"%s>',
esc_attr( $f['type'] ), esc_attr( $name ), esc_attr( $name ), esc_attr( $value ),
'number' === $f['type'] ? 'small-text' : 'regular-text',
esc_attr( $f['placeholder'] ?? '' ),
'number' === $f['type'] ? ' min="0" step="1"' : ''
);
}
echo '</td></tr>';
}
echo '</tbody></table>';
echo '<p class="description">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.</p>';
echo '<p class="description">Consejo: la foto principal aparece en los listados. Añade más fotos en el contenido con el bloque «Galería».</p>';
}
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 '<div class="ga-grid">';
}
while ( $q->have_posts() ) {
$q->the_post();
ga_animal_card();
}
$carousel ? ga_carousel_close() : print( '</div>' );
} else {
echo '<p class="ga-empty">' . esc_html( ga__( 'Ahora mismo no hay animales en esta sección. ¡Vuelve pronto!', 'Une honetan ez dago animaliarik atal honetan. Itzuli laster!' ) ) . '</p>';
}
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(
'<div class="ga-carousel" data-ga-carousel role="region" aria-roledescription="%s" aria-label="%s"><div class="ga-carousel__track" tabindex="0">',
esc_attr( ga__( 'carrusel', 'karrusela' ) ),
esc_attr( $label ?: ga__( 'Animales', 'Animaliak' ) )
);
}
function ga_carousel_close() {
printf(
'</div><div class="ga-carousel__nav"><button type="button" class="ga-carousel__btn" data-dir="-1" aria-label="%s">←</button><button type="button" class="ga-carousel__btn" data-dir="1" aria-label="%s">→</button></div></div>',
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( '<article class="ga-card"><a href="%s">%s</a></article>', 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 '<div class="ga-notice ga-notice--ok" role="status"><strong>' . esc_html( ga__( '¡Eskerrik asko!', 'Eskerrik asko!' ) ) . '</strong> '
. esc_html( ga__( 'Hemos recibido tu mensaje y te responderemos lo antes posible.', 'Zure mezua jaso dugu eta ahalik eta lasterren erantzungo dizugu.' ) ) . '</div>';
} elseif ( 'error' === $status ) {
echo '<div class="ga-notice ga-notice--error" role="alert">'
. esc_html( ga__( 'No hemos podido enviar el mensaje. Revisa los campos obligatorios o escríbenos a ', 'Ezin izan dugu mezua bidali. Egiaztatu derrigorrezko eremuak edo idatzi iezaguzu helbide honetara: ' ) . ga_info( 'email' ) ) . '</div>';
}
?>
<form class="ga-form" method="post" action="<?php echo esc_url( admin_url( 'admin-post.php' ) ); ?>">
<input type="hidden" name="action" value="ga_contacto">
<input type="hidden" name="idioma" value="<?php echo esc_attr( ga_lang() ); ?>">
<input type="hidden" name="redirect" value="<?php echo esc_url( get_permalink() ); ?>">
<?php wp_nonce_field( 'ga_contacto', 'ga_nonce' ); ?>
<div class="ga-hp" aria-hidden="true"><label>No rellenar <input type="text" name="web" tabindex="-1" autocomplete="off"></label></div>
<div class="ga-form__row">
<label><?php ga_e( 'Nombre', 'Izena' ); ?> *<input type="text" name="nombre" required autocomplete="name"></label>
<label><?php ga_e( 'Email', 'Posta elektronikoa' ); ?> *<input type="email" name="email" required autocomplete="email"></label>
</div>
<div class="ga-form__row">
<label><?php ga_e( 'Teléfono', 'Telefonoa' ); ?><input type="tel" name="telefono" autocomplete="tel"></label>
<label><?php ga_e( 'Motivo', 'Arrazoia' ); ?>
<select name="motivo">
<?php foreach ( ga_contact_reasons() as $value => $label ) : ?>
<option value="<?php echo esc_attr( $value ); ?>" <?php selected( $preselect, $value ); ?>><?php echo esc_html( $label ); ?></option>
<?php endforeach; ?>
</select>
</label>
</div>
<label><?php ga_e( 'Animal por el que preguntas', 'Zein animaliari buruz galdetzen duzu' ); ?>
<input type="text" name="animal" value="<?php echo esc_attr( $animal ); ?>" placeholder="<?php echo esc_attr( ga__( 'Opcional', 'Aukerakoa' ) ); ?>">
</label>
<label><?php ga_e( 'Mensaje', 'Mezua' ); ?> *
<textarea name="mensaje" rows="6" required placeholder="<?php echo $animal ? esc_attr( ga__( 'Cuéntanos un poco sobre ti, tu casa y tu día a día…', 'Kontaiguzu zerbait zuri buruz, zure etxeari eta eguneroko bizitzari buruz…' ) ) : ''; ?>"></textarea>
</label>
<label class="ga-form__check">
<input type="checkbox" name="privacidad" value="1" required>
<span>
<?php if ( 'eu' === ga_lang() ) : ?>
<a href="<?php echo esc_url( $privacy ); ?>" target="_blank">Pribatutasun-politika</a> irakurri eta onartzen dut. *
<?php else : ?>
He leído y acepto la <a href="<?php echo esc_url( $privacy ); ?>" target="_blank">política de privacidad</a>. *
<?php endif; ?>
</span>
</label>
<button type="submit" class="ga-btn"><?php ga_e( 'Enviar mensaje', 'Mezua bidali' ); ?></button>
</form>
<?php
return ob_get_clean();
} );
add_action( 'admin_post_nopriv_ga_contacto', 'ga_handle_contact' );
add_action( 'admin_post_ga_contacto', 'ga_handle_contact' );
function ga_handle_contact() {
$redirect = wp_validate_redirect( esc_url_raw( wp_unslash( $_POST['redirect'] ?? '' ) ), home_url( '/' ) );
$go = function ( $status ) use ( $redirect ) {
wp_safe_redirect( add_query_arg( 'enviado', $status, $redirect ) . '#formulario' );
exit;
};
if ( ! isset( $_POST['ga_nonce'] ) || ! wp_verify_nonce( $_POST['ga_nonce'], 'ga_contacto' ) ) {
$go( 'error' );
}
// Honeypot: los bots rellenan el campo oculto; fingimos éxito.
if ( ! empty( $_POST['web'] ) ) {
$go( 'ok' );
}
$reasons = ga_contact_reasons(); // En castellano: el admin_post se ejecuta en contexto de administración.
$reason = sanitize_key( $_POST['motivo'] ?? '' );
$data = array(
'nombre' => 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' );
}